/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
 *
 *   The original version of this source code and documentation is copyrighted
 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
 * materials are provided under terms of a License Agreement between Taligent
 * and Sun. This technology is protected by multiple US and International
 * patents. This notice and attribution to Taligent may not be removed.
 *   Taligent is a registered trademark of Taligent, Inc.
 *
 */

package java.util;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PermissionCollection;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import sun.util.BuddhistCalendar;
import sun.util.calendar.ZoneInfo;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.spi.CalendarProvider;

/**
 * The <code>Calendar</code> class is an abstract class that provides methods
 * for converting between a specific instant in time and a set of {@link
 * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
 * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
 * manipulating the calendar fields, such as getting the date of the next
 * week. An instant in time can be represented by a millisecond value that is
 * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
 * 00:00:00.000 GMT (Gregorian).
 *
 * <p>The class also provides additional fields and methods for
 * implementing a concrete calendar system outside the package. Those
 * fields and methods are defined as <code>protected</code>.
 *
 * <p>
 * Like other locale-sensitive classes, <code>Calendar</code> provides a
 * class method, <code>getInstance</code>, for getting a generally useful
 * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
 * returns a <code>Calendar</code> object whose
 * calendar fields have been initialized with the current date and time:
 * <blockquote>
 * <pre>
 *     Calendar rightNow = Calendar.getInstance();
 * </pre>
 * </blockquote>
 *
 * <p>A <code>Calendar</code> object can produce all the calendar field values
 * needed to implement the date-time formatting for a particular language and
 * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
 * <code>Calendar</code> defines the range of values returned by
 * certain calendar fields, as well as their meaning.  For example,
 * the first month of the calendar system has value <code>MONTH ==
 * JANUARY</code> for all calendars.  Other values are defined by the
 * concrete subclass, such as <code>ERA</code>.  See individual field
 * documentation and subclass documentation for details.
 *
 * <h3>Getting and Setting Calendar Field Values</h3>
 *
 * <p>The calendar field values can be set by calling the <code>set</code>
 * methods. Any field values set in a <code>Calendar</code> will not be
 * interpreted until it needs to calculate its time value (milliseconds from
 * the Epoch) or values of the calendar fields. Calling the
 * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
 * <code>add</code> and <code>roll</code> involves such calculation.
 *
 * <h4>Leniency</h4>
 *
 * <p><code>Calendar</code> has two modes for interpreting the calendar
 * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
 * <code>Calendar</code> is in lenient mode, it accepts a wider range of
 * calendar field values than it produces.  When a <code>Calendar</code>
 * recomputes calendar field values for return by <code>get()</code>, all of
 * the calendar fields are normalized. For example, a lenient
 * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
 * <code>DAY_OF_MONTH == 32</code> as February 1.
 *
 * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
 * exception if there is any inconsistency in its calendar fields. For
 * example, a <code>GregorianCalendar</code> always produces
 * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
 * non-lenient <code>GregorianCalendar</code> throws an exception upon
 * calculating its time or calendar field values if any out-of-range field
 * value has been set.
 *
 * <h4><a name="first_week">First Week</a></h4>
 *
 * <code>Calendar</code> defines a locale-specific seven day week using two
 * parameters: the first day of the week and the minimal days in first week
 * (from 1 to 7).  These numbers are taken from the locale resource data when a
 * <code>Calendar</code> is constructed.  They may also be specified explicitly
 * through the methods for setting their values.
 *
 * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
 * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
 * first week of the month or year as a reference point.  The first week of a
 * month or year is defined as the earliest seven day period beginning on
 * <code>getFirstDayOfWeek()</code> and containing at least
 * <code>getMinimalDaysInFirstWeek()</code> days of that month or year.  Weeks
 * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
 * it.  Note that the normalized numbering returned by <code>get()</code> may be
 * different.  For example, a specific <code>Calendar</code> subclass may
 * designate the week before week 1 of a year as week <code><i>n</i></code> of
 * the previous year.
 *
 * <h4>Calendar Fields Resolution</h4>
 *
 * When computing a date and time from the calendar fields, there
 * may be insufficient information for the computation (such as only
 * year and month with no day of month), or there may be inconsistent
 * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
 * 1996 is actually a Monday). <code>Calendar</code> will resolve
 * calendar field values to determine the date and time in the
 * following way.
 *
 * <p><a name="resolution">If there is any conflict in calendar field values,
 * <code>Calendar</code> gives priorities to calendar fields that have been set
 * more recently.</a> The following are the default combinations of the
 * calendar fields. The most recent combination, as determined by the
 * most recently set single field, will be used.
 *
 * <p><a name="date_resolution">For the date fields</a>:
 * <blockquote>
 * <pre>
 * YEAR + MONTH + DAY_OF_MONTH
 * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 * YEAR + DAY_OF_YEAR
 * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
 * </pre></blockquote>
 *
 * <a name="time_resolution">For the time of day fields</a>:
 * <blockquote>
 * <pre>
 * HOUR_OF_DAY
 * AM_PM + HOUR
 * </pre></blockquote>
 *
 * <p>If there are any calendar fields whose values haven't been set in the selected
 * field combination, <code>Calendar</code> uses their default values. The default
 * value of each field may vary by concrete calendar systems. For example, in
 * <code>GregorianCalendar</code>, the default of a field is the same as that
 * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
 * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
 *
 * <p>
 * <strong>Note:</strong> There are certain possible ambiguities in
 * interpretation of certain singular times, which are resolved in the
 * following ways:
 * <ol>
 * <li> 23:59 is the last minute of the day and 00:00 is the first
 * minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
 * Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
 *
 * <li> Although historically not precise, midnight also belongs to "am",
 * and noon belongs to "pm", so on the same day,
 * 12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
 * </ol>
 *
 * <p>
 * The date or time format strings are not part of the definition of a
 * calendar, as those must be modifiable or overridable by the user at
 * runtime. Use {@link DateFormat}
 * to format dates.
 *
 * <h4>Field Manipulation</h4>
 *
 * The calendar fields can be changed using three methods:
 * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.
 *
 * <p><strong><code>set(f, value)</code></strong> changes calendar field
 * <code>f</code> to <code>value</code>.  In addition, it sets an
 * internal member variable to indicate that calendar field <code>f</code> has
 * been changed. Although calendar field <code>f</code> is changed immediately,
 * the calendar's time value in milliseconds is not recomputed until the next call to
 * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
 * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
 * <code>set()</code> do not trigger multiple, unnecessary
 * computations. As a result of changing a calendar field using
 * <code>set()</code>, other calendar fields may also change, depending on the
 * calendar field, the calendar field value, and the calendar system. In addition,
 * <code>get(f)</code> will not necessarily return <code>value</code> set by
 * the call to the <code>set</code> method
 * after the calendar fields have been recomputed. The specifics are determined by
 * the concrete calendar class.</p>
 *
 * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
 * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
 * Calendar.SEPTEMBER)</code> sets the date to September 31,
 * 1999. This is a temporary internal representation that resolves to
 * October 1, 1999 if <code>getTime()</code>is then called. However, a
 * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
 * <code>getTime()</code> sets the date to September 30, 1999, since
 * no recomputation occurs after <code>set()</code> itself.</p>
 *
 * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
 * to field <code>f</code>.  This is equivalent to calling <code>set(f,
 * get(f) + delta)</code> with two adjustments:</p>
 *
 * <blockquote>
 * <p><strong>Add rule 1</strong>. The value of field <code>f</code>
 * after the call minus the value of field <code>f</code> before the
 * call is <code>delta</code>, modulo any overflow that has occurred in
 * field <code>f</code>. Overflow occurs when a field value exceeds its
 * range and, as a result, the next larger field is incremented or
 * decremented and the field value is adjusted back into its range.</p>
 *
 * <p><strong>Add rule 2</strong>. If a smaller field is expected to be
 * invariant, but it is impossible for it to be equal to its
 * prior value because of changes in its minimum or maximum after field
 * <code>f</code> is changed or other constraints, such as time zone
 * offset changes, then its value is adjusted to be as close
 * as possible to its expected value. A smaller field represents a
 * smaller unit of time. <code>HOUR</code> is a smaller field than
 * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
 * that are not expected to be invariant. The calendar system
 * determines what fields are expected to be invariant.</p>
 * </blockquote>
 *
 * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
 * an immediate recomputation of the calendar's milliseconds and all
 * fields.</p>
 *
 * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
 * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
 * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
 * 1</strong> sets the <code>MONTH</code> field to September, since
 * adding 13 months to August gives September of the next year. Since
 * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
 * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
 * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
 * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
 * rule 2, since it is expected to change when the month changes in a
 * <code>GregorianCalendar</code>.</p>
 *
 * <p><strong><code>roll(f, delta)</code></strong> adds
 * <code>delta</code> to field <code>f</code> without changing larger
 * fields. This is equivalent to calling <code>add(f, delta)</code> with
 * the following adjustment:</p>
 *
 * <blockquote>
 * <p><strong>Roll rule</strong>. Larger fields are unchanged after the
 * call. A larger field represents a larger unit of
 * time. <code>DAY_OF_MONTH</code> is a larger field than
 * <code>HOUR</code>.</p>
 * </blockquote>
 *
 * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
 *
 * <p><strong>Usage model</strong>. To motivate the behavior of
 * <code>add()</code> and <code>roll()</code>, consider a user interface
 * component with increment and decrement buttons for the month, day, and
 * year, and an underlying <code>GregorianCalendar</code>. If the
 * interface reads January 31, 1999 and the user presses the month
 * increment button, what should it read? If the underlying
 * implementation uses <code>set()</code>, it might read March 3, 1999. A
 * better result would be February 28, 1999. Furthermore, if the user
 * presses the month increment button again, it should read March 31,
 * 1999, not March 28, 1999. By saving the original date and using either
 * <code>add()</code> or <code>roll()</code>, depending on whether larger
 * fields should be affected, the user interface can behave as most users
 * will intuitively expect.</p>
 *
 * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
 * @see java.lang.System#currentTimeMillis()
 * @see Date
 * @see GregorianCalendar
 * @see TimeZone
 * @see java.text.DateFormat
 * @since JDK1.1
 */
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {

  // Data flow in Calendar
  // ---------------------

  // The current time is represented in two ways by Calendar: as UTC
  // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
  // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
  // millis from the fields, and vice versa.  The data needed to do this
  // conversion is encapsulated by a TimeZone object owned by the Calendar.
  // The data provided by the TimeZone object may also be overridden if the
  // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
  // keeps track of what information was most recently set by the caller, and
  // uses that to compute any other information as needed.

  // If the user sets the fields using set(), the data flow is as follows.
  // This is implemented by the Calendar subclass's computeTime() method.
  // During this process, certain fields may be ignored.  The disambiguation
  // algorithm for resolving which fields to pay attention to is described
  // in the class documentation.

  //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
  //           |
  //           | Using Calendar-specific algorithm
  //           V
  //   local standard millis
  //           |
  //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
  //           V
  //   UTC millis (in time data member)

  // If the user sets the UTC millis using setTime() or setTimeInMillis(),
  // the data flow is as follows.  This is implemented by the Calendar
  // subclass's computeFields() method.

  //   UTC millis (in time data member)
  //           |
  //           | Using TimeZone getOffset()
  //           V
  //   local standard millis
  //           |
  //           | Using Calendar-specific algorithm
  //           V
  //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)

  // In general, a round trip from fields, through local and UTC millis, and
  // back out to fields is made when necessary.  This is implemented by the
  // complete() method.  Resolving a partial set of fields into a UTC millis
  // value allows all remaining fields to be generated from that value.  If
  // the Calendar is lenient, the fields are also renormalized to standard
  // ranges when they are regenerated.

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
   * value; see subclass documentation.
   *
   * @see GregorianCalendar#AD
   * @see GregorianCalendar#BC
   */
  public final static int ERA = 0;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * year. This is a calendar-specific value; see subclass documentation.
   */
  public final static int YEAR = 1;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * month. This is a calendar-specific value. The first month of
   * the year in the Gregorian and Julian calendars is
   * <code>JANUARY</code> which is 0; the last depends on the number
   * of months in a year.
   *
   * @see #JANUARY
   * @see #FEBRUARY
   * @see #MARCH
   * @see #APRIL
   * @see #MAY
   * @see #JUNE
   * @see #JULY
   * @see #AUGUST
   * @see #SEPTEMBER
   * @see #OCTOBER
   * @see #NOVEMBER
   * @see #DECEMBER
   * @see #UNDECIMBER
   */
  public final static int MONTH = 2;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * week number within the current year.  The first week of the year, as
   * defined by <code>getFirstDayOfWeek()</code> and
   * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
   * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
   * the year.
   *
   * @see #getFirstDayOfWeek
   * @see #getMinimalDaysInFirstWeek
   */
  public final static int WEEK_OF_YEAR = 3;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * week number within the current month.  The first week of the month, as
   * defined by <code>getFirstDayOfWeek()</code> and
   * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
   * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
   * the month.
   *
   * @see #getFirstDayOfWeek
   * @see #getMinimalDaysInFirstWeek
   */
  public final static int WEEK_OF_MONTH = 4;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
   * The first day of the month has value 1.
   *
   * @see #DAY_OF_MONTH
   */
  public final static int DATE = 5;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * day of the month. This is a synonym for <code>DATE</code>.
   * The first day of the month has value 1.
   *
   * @see #DATE
   */
  public final static int DAY_OF_MONTH = 5;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the day
   * number within the current year.  The first day of the year has value 1.
   */
  public final static int DAY_OF_YEAR = 6;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the day
   * of the week.  This field takes values <code>SUNDAY</code>,
   * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
   * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
   *
   * @see #SUNDAY
   * @see #MONDAY
   * @see #TUESDAY
   * @see #WEDNESDAY
   * @see #THURSDAY
   * @see #FRIDAY
   * @see #SATURDAY
   */
  public final static int DAY_OF_WEEK = 7;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * ordinal number of the day of the week within the current month. Together
   * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
   * within a month.  Unlike <code>WEEK_OF_MONTH</code> and
   * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
   * <code>getFirstDayOfWeek()</code> or
   * <code>getMinimalDaysInFirstWeek()</code>.  <code>DAY_OF_MONTH 1</code>
   * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
   * 1</code>; <code>8</code> through <code>14</code> correspond to
   * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
   * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
   * <code>DAY_OF_WEEK_IN_MONTH 1</code>.  Negative values count back from the
   * end of the month, so the last Sunday of a month is specified as
   * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>.  Because
   * negative values count backward they will usually be aligned differently
   * within the month than positive values.  For example, if a month has 31
   * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
   * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
   *
   * @see #DAY_OF_WEEK
   * @see #WEEK_OF_MONTH
   */
  public final static int DAY_OF_WEEK_IN_MONTH = 8;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating
   * whether the <code>HOUR</code> is before or after noon.
   * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
   *
   * @see #AM
   * @see #PM
   * @see #HOUR
   */
  public final static int AM_PM = 9;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * hour of the morning or afternoon. <code>HOUR</code> is used for the
   * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
   * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
   *
   * @see #AM_PM
   * @see #HOUR_OF_DAY
   */
  public final static int HOUR = 10;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
   * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
   *
   * @see #HOUR
   */
  public final static int HOUR_OF_DAY = 11;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * minute within the hour.
   * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
   */
  public final static int MINUTE = 12;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * second within the minute.
   * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
   */
  public final static int SECOND = 13;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * millisecond within the second.
   * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
   */
  public final static int MILLISECOND = 14;

  /**
   * Field number for <code>get</code> and <code>set</code>
   * indicating the raw offset from GMT in milliseconds.
   * <p>
   * This field reflects the correct GMT offset value of the time
   * zone of this <code>Calendar</code> if the
   * <code>TimeZone</code> implementation subclass supports
   * historical GMT offset changes.
   */
  public final static int ZONE_OFFSET = 15;

  /**
   * Field number for <code>get</code> and <code>set</code> indicating the
   * daylight saving offset in milliseconds.
   * <p>
   * This field reflects the correct daylight saving offset value of
   * the time zone of this <code>Calendar</code> if the
   * <code>TimeZone</code> implementation subclass supports
   * historical Daylight Saving Time schedule changes.
   */
  public final static int DST_OFFSET = 16;

  /**
   * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
   * Field numbers range from <code>0..FIELD_COUNT-1</code>.
   */
  public final static int FIELD_COUNT = 17;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Sunday.
   */
  public final static int SUNDAY = 1;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Monday.
   */
  public final static int MONDAY = 2;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Tuesday.
   */
  public final static int TUESDAY = 3;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Wednesday.
   */
  public final static int WEDNESDAY = 4;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Thursday.
   */
  public final static int THURSDAY = 5;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Friday.
   */
  public final static int FRIDAY = 6;

  /**
   * Value of the {@link #DAY_OF_WEEK} field indicating
   * Saturday.
   */
  public final static int SATURDAY = 7;

  /**
   * Value of the {@link #MONTH} field indicating the
   * first month of the year in the Gregorian and Julian calendars.
   */
  public final static int JANUARY = 0;

  /**
   * Value of the {@link #MONTH} field indicating the
   * second month of the year in the Gregorian and Julian calendars.
   */
  public final static int FEBRUARY = 1;

  /**
   * Value of the {@link #MONTH} field indicating the
   * third month of the year in the Gregorian and Julian calendars.
   */
  public final static int MARCH = 2;

  /**
   * Value of the {@link #MONTH} field indicating the
   * fourth month of the year in the Gregorian and Julian calendars.
   */
  public final static int APRIL = 3;

  /**
   * Value of the {@link #MONTH} field indicating the
   * fifth month of the year in the Gregorian and Julian calendars.
   */
  public final static int MAY = 4;

  /**
   * Value of the {@link #MONTH} field indicating the
   * sixth month of the year in the Gregorian and Julian calendars.
   */
  public final static int JUNE = 5;

  /**
   * Value of the {@link #MONTH} field indicating the
   * seventh month of the year in the Gregorian and Julian calendars.
   */
  public final static int JULY = 6;

  /**
   * Value of the {@link #MONTH} field indicating the
   * eighth month of the year in the Gregorian and Julian calendars.
   */
  public final static int AUGUST = 7;

  /**
   * Value of the {@link #MONTH} field indicating the
   * ninth month of the year in the Gregorian and Julian calendars.
   */
  public final static int SEPTEMBER = 8;

  /**
   * Value of the {@link #MONTH} field indicating the
   * tenth month of the year in the Gregorian and Julian calendars.
   */
  public final static int OCTOBER = 9;

  /**
   * Value of the {@link #MONTH} field indicating the
   * eleventh month of the year in the Gregorian and Julian calendars.
   */
  public final static int NOVEMBER = 10;

  /**
   * Value of the {@link #MONTH} field indicating the
   * twelfth month of the year in the Gregorian and Julian calendars.
   */
  public final static int DECEMBER = 11;

  /**
   * Value of the {@link #MONTH} field indicating the
   * thirteenth month of the year. Although <code>GregorianCalendar</code>
   * does not use this value, lunar calendars do.
   */
  public final static int UNDECIMBER = 12;

  /**
   * Value of the {@link #AM_PM} field indicating the
   * period of the day from midnight to just before noon.
   */
  public final static int AM = 0;

  /**
   * Value of the {@link #AM_PM} field indicating the
   * period of the day from noon to just before midnight.
   */
  public final static int PM = 1;

  /**
   * A style specifier for {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating names in all styles, such as
   * "January" and "Jan".
   *
   * @see #SHORT_FORMAT
   * @see #LONG_FORMAT
   * @see #SHORT_STANDALONE
   * @see #LONG_STANDALONE
   * @see #SHORT
   * @see #LONG
   * @since 1.6
   */
  public static final int ALL_STYLES = 0;

  static final int STANDALONE_MASK = 0x8000;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} equivalent to {@link #SHORT_FORMAT}.
   *
   * @see #SHORT_STANDALONE
   * @see #LONG
   * @since 1.6
   */
  public static final int SHORT = 1;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} equivalent to {@link #LONG_FORMAT}.
   *
   * @see #LONG_STANDALONE
   * @see #SHORT
   * @since 1.6
   */
  public static final int LONG = 2;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a narrow name used for format. Narrow names
   * are typically single character strings, such as "M" for Monday.
   *
   * @see #NARROW_STANDALONE
   * @see #SHORT_FORMAT
   * @see #LONG_FORMAT
   * @since 1.8
   */
  public static final int NARROW_FORMAT = 4;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a narrow name independently. Narrow names
   * are typically single character strings, such as "M" for Monday.
   *
   * @see #NARROW_FORMAT
   * @see #SHORT_STANDALONE
   * @see #LONG_STANDALONE
   * @since 1.8
   */
  public static final int NARROW_STANDALONE = NARROW_FORMAT | STANDALONE_MASK;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a short name used for format.
   *
   * @see #SHORT_STANDALONE
   * @see #LONG_FORMAT
   * @see #LONG_STANDALONE
   * @since 1.8
   */
  public static final int SHORT_FORMAT = 1;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a long name used for format.
   *
   * @see #LONG_STANDALONE
   * @see #SHORT_FORMAT
   * @see #SHORT_STANDALONE
   * @since 1.8
   */
  public static final int LONG_FORMAT = 2;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a short name used independently,
   * such as a month abbreviation as calendar headers.
   *
   * @see #SHORT_FORMAT
   * @see #LONG_FORMAT
   * @see #LONG_STANDALONE
   * @since 1.8
   */
  public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK;

  /**
   * A style specifier for {@link #getDisplayName(int, int, Locale)
   * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
   * getDisplayNames} indicating a long name used independently,
   * such as a month name as calendar headers.
   *
   * @see #LONG_FORMAT
   * @see #SHORT_FORMAT
   * @see #SHORT_STANDALONE
   * @since 1.8
   */
  public static final int LONG_STANDALONE = LONG | STANDALONE_MASK;

  // Internal notes:
  // Calendar contains two kinds of time representations: current "time" in
  // milliseconds, and a set of calendar "fields" representing the current time.
  // The two representations are usually in sync, but can get out of sync
  // as follows.
  // 1. Initially, no fields are set, and the time is invalid.
  // 2. If the time is set, all fields are computed and in sync.
  // 3. If a single field is set, the time is invalid.
  // Recomputation of the time and fields happens when the object needs
  // to return a result to the user, or use a result for a computation.

  /**
   * The calendar field values for the currently set time for this calendar.
   * This is an array of <code>FIELD_COUNT</code> integers, with index values
   * <code>ERA</code> through <code>DST_OFFSET</code>.
   *
   * @serial
   */
  @SuppressWarnings("ProtectedField")
  protected int fields[];

  /**
   * The flags which tell if a specified calendar field for the calendar is set.
   * A new object has no fields set.  After the first call to a method
   * which generates the fields, they all remain set after that.
   * This is an array of <code>FIELD_COUNT</code> booleans, with index values
   * <code>ERA</code> through <code>DST_OFFSET</code>.
   *
   * @serial
   */
  @SuppressWarnings("ProtectedField")
  protected boolean isSet[];

  /**
   * Pseudo-time-stamps which specify when each field was set. There
   * are two special values, UNSET and COMPUTED. Values from
   * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
   */
  transient private int stamp[];

  /**
   * The currently set time for this calendar, expressed in milliseconds after
   * January 1, 1970, 0:00:00 GMT.
   *
   * @serial
   * @see #isTimeSet
   */
  @SuppressWarnings("ProtectedField")
  protected long time;

  /**
   * True if then the value of <code>time</code> is valid.
   * The time is made invalid by a change to an item of <code>field[]</code>.
   *
   * @serial
   * @see #time
   */
  @SuppressWarnings("ProtectedField")
  protected boolean isTimeSet;

  /**
   * True if <code>fields[]</code> are in sync with the currently set time.
   * If false, then the next attempt to get the value of a field will
   * force a recomputation of all fields from the current value of
   * <code>time</code>.
   *
   * @serial
   */
  @SuppressWarnings("ProtectedField")
  protected boolean areFieldsSet;

  /**
   * True if all fields have been set.
   *
   * @serial
   */
  transient boolean areAllFieldsSet;

  /**
   * <code>True</code> if this calendar allows out-of-range field values during computation
   * of <code>time</code> from <code>fields[]</code>.
   *
   * @serial
   * @see #setLenient
   * @see #isLenient
   */
  private boolean lenient = true;

  /**
   * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
   * uses the time zone data to translate between locale and GMT time.
   *
   * @serial
   */
  private TimeZone zone;

  /**
   * <code>True</code> if zone references to a shared TimeZone object.
   */
  transient private boolean sharedZone = false;

  /**
   * The first day of the week, with possible values <code>SUNDAY</code>,
   * <code>MONDAY</code>, etc.  This is a locale-dependent value.
   *
   * @serial
   */
  private int firstDayOfWeek;

  /**
   * The number of days required for the first week in a month or year,
   * with possible values from 1 to 7.  This is a locale-dependent value.
   *
   * @serial
   */
  private int minimalDaysInFirstWeek;

  /**
   * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
   * of a Locale.
   */
  private static final ConcurrentMap<Locale, int[]> cachedLocaleData
      = new ConcurrentHashMap<>(3);

  // Special values of stamp[]
  /**
   * The corresponding fields[] has no value.
   */
  private static final int UNSET = 0;

  /**
   * The value of the corresponding fields[] has been calculated internally.
   */
  private static final int COMPUTED = 1;

  /**
   * The value of the corresponding fields[] has been set externally. Stamp
   * values which are greater than 1 represents the (pseudo) time when the
   * corresponding fields[] value was set.
   */
  private static final int MINIMUM_USER_STAMP = 2;

  /**
   * The mask value that represents all of the fields.
   */
  static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;

  /**
   * The next available value for <code>stamp[]</code>, an internal array.
   * This actually should not be written out to the stream, and will probably
   * be removed from the stream in the near future.  In the meantime,
   * a value of <code>MINIMUM_USER_STAMP</code> should be used.
   *
   * @serial
   */
  private int nextStamp = MINIMUM_USER_STAMP;

  // the internal serial version which says which version was written
  // - 0 (default) for version up to JDK 1.1.5
  // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
  //     as well as compatible values for other fields.  This is a
  //     transitional format.
  // - 2 (not implemented yet) a future version, in which fields[],
  //     areFieldsSet, and isTimeSet become transient, and isSet[] is
  //     removed. In JDK 1.1.6 we write a format compatible with version 2.
  static final int currentSerialVersion = 1;

  /**
   * The version of the serialized data on the stream.  Possible values:
   * <dl>
   * <dt><b>0</b> or not present on stream</dt>
   * <dd>
   * JDK 1.1.5 or earlier.
   * </dd>
   * <dt><b>1</b></dt>
   * <dd>
   * JDK 1.1.6 or later.  Writes a correct 'time' value
   * as well as compatible values for other fields.  This is a
   * transitional format.
   * </dd>
   * </dl>
   * When streaming out this class, the most recent format
   * and the highest allowable <code>serialVersionOnStream</code>
   * is written.
   *
   * @serial
   * @since JDK1.1.6
   */
  private int serialVersionOnStream = currentSerialVersion;

  // Proclaim serialization compatibility with JDK 1.1
  static final long serialVersionUID = -1807547505821590642L;

  // Mask values for calendar fields
  @SuppressWarnings("PointlessBitwiseExpression")
  final static int ERA_MASK = (1 << ERA);
  final static int YEAR_MASK = (1 << YEAR);
  final static int MONTH_MASK = (1 << MONTH);
  final static int WEEK_OF_YEAR_MASK = (1 << WEEK_OF_YEAR);
  final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
  final static int DAY_OF_MONTH_MASK = (1 << DAY_OF_MONTH);
  final static int DATE_MASK = DAY_OF_MONTH_MASK;
  final static int DAY_OF_YEAR_MASK = (1 << DAY_OF_YEAR);
  final static int DAY_OF_WEEK_MASK = (1 << DAY_OF_WEEK);
  final static int DAY_OF_WEEK_IN_MONTH_MASK = (1 << DAY_OF_WEEK_IN_MONTH);
  final static int AM_PM_MASK = (1 << AM_PM);
  final static int HOUR_MASK = (1 << HOUR);
  final static int HOUR_OF_DAY_MASK = (1 << HOUR_OF_DAY);
  final static int MINUTE_MASK = (1 << MINUTE);
  final static int SECOND_MASK = (1 << SECOND);
  final static int MILLISECOND_MASK = (1 << MILLISECOND);
  final static int ZONE_OFFSET_MASK = (1 << ZONE_OFFSET);
  final static int DST_OFFSET_MASK = (1 << DST_OFFSET);

  /**
   * {@code Calendar.Builder} is used for creating a {@code Calendar} from
   * various date-time parameters.
   *
   * <p>There are two ways to set a {@code Calendar} to a date-time value. One
   * is to set the instant parameter to a millisecond offset from the <a
   * href="Calendar.html#Epoch">Epoch</a>. The other is to set individual
   * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired
   * values. These two ways can't be mixed. Trying to set both the instant and
   * individual fields will cause an {@link IllegalStateException} to be
   * thrown. However, it is permitted to override previous values of the
   * instant or field parameters.
   *
   * <p>If no enough field parameters are given for determining date and/or
   * time, calendar specific default values are used when building a
   * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value
   * isn't given for the Gregorian calendar, 1970 will be used. If there are
   * any conflicts among field parameters, the <a
   * href="Calendar.html#resolution"> resolution rules</a> are applied.
   * Therefore, the order of field setting matters.
   *
   * <p>In addition to the date-time parameters,
   * the {@linkplain #setLocale(Locale) locale},
   * {@linkplain #setTimeZone(TimeZone) time zone},
   * {@linkplain #setWeekDefinition(int, int) week definition}, and
   * {@linkplain #setLenient(boolean) leniency mode} parameters can be set.
   *
   * <p><b>Examples</b>
   * <p>The following are sample usages. Sample code assumes that the
   * {@code Calendar} constants are statically imported.
   *
   * <p>The following code produces a {@code Calendar} with date 2012-12-31
   * (Gregorian) because Monday is the first day of a week with the <a
   * href="GregorianCalendar.html#iso8601_compatible_setting"> ISO 8601
   * compatible week parameters</a>.
   * <pre>
   *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
   *                        .setWeekDate(2013, 1, MONDAY).build();</pre>
   * <p>The following code produces a Japanese {@code Calendar} with date
   * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA}
   * is <em>Heisei</em> that started on that day.
   * <pre>
   *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
   *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();</pre>
   *
   * @see Calendar#getInstance(TimeZone, Locale)
   * @see Calendar#fields
   * @since 1.8
   */
  public static class Builder {

    private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
    private static final int WEEK_YEAR = FIELD_COUNT;

    private long instant;
    // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined
    private int[] fields;
    // Pseudo timestamp starting from MINIMUM_USER_STAMP.
    // (COMPUTED is used to indicate that the instant has been set.)
    private int nextStamp;
    // maxFieldIndex keeps the max index of fields which have been set.
    // (WEEK_YEAR is never included.)
    private int maxFieldIndex;
    private String type;
    private TimeZone zone;
    private boolean lenient = true;
    private Locale locale;
    private int firstDayOfWeek, minimalDaysInFirstWeek;

    /**
     * Constructs a {@code Calendar.Builder}.
     */
    public Builder() {
    }

    /**
     * Sets the instant parameter to the given {@code instant} value that is
     * a millisecond offset from <a href="Calendar.html#Epoch">the
     * Epoch</a>.
     *
     * @param instant a millisecond offset from the Epoch
     * @return this {@code Calendar.Builder}
     * @throws IllegalStateException if any of the field parameters have already been set
     * @see Calendar#setTime(Date)
     * @see Calendar#setTimeInMillis(long)
     * @see Calendar#time
     */
    public Builder setInstant(long instant) {
      if (fields != null) {
        throw new IllegalStateException();
      }
      this.instant = instant;
      nextStamp = COMPUTED;
      return this;
    }

    /**
     * Sets the instant parameter to the {@code instant} value given by a
     * {@link Date}. This method is equivalent to a call to
     * {@link #setInstant(long) setInstant(instant.getTime())}.
     *
     * @param instant a {@code Date} representing a millisecond offset from the Epoch
     * @return this {@code Calendar.Builder}
     * @throws NullPointerException if {@code instant} is {@code null}
     * @throws IllegalStateException if any of the field parameters have already been set
     * @see Calendar#setTime(Date)
     * @see Calendar#setTimeInMillis(long)
     * @see Calendar#time
     */
    public Builder setInstant(Date instant) {
      return setInstant(instant.getTime()); // NPE if instant == null
    }

    /**
     * Sets the {@code field} parameter to the given {@code value}.
     * {@code field} is an index to the {@link Calendar#fields}, such as
     * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is
     * not performed in this method. Any out of range values are either
     * normalized in lenient mode or detected as an invalid value in
     * non-lenient mode when building a {@code Calendar}.
     *
     * @param field an index to the {@code Calendar} fields
     * @param value the field value
     * @return this {@code Calendar.Builder}
     * @throws IllegalArgumentException if {@code field} is invalid
     * @throws IllegalStateException if the instant value has already been set, or if fields have
     * been set too many (approximately {@link Integer#MAX_VALUE}) times.
     * @see Calendar#set(int, int)
     */
    public Builder set(int field, int value) {
      // Note: WEEK_YEAR can't be set with this method.
      if (field < 0 || field >= FIELD_COUNT) {
        throw new IllegalArgumentException("field is invalid");
      }
      if (isInstantSet()) {
        throw new IllegalStateException("instant has been set");
      }
      allocateFields();
      internalSet(field, value);
      return this;
    }

    /**
     * Sets field parameters to their values given by
     * {@code fieldValuePairs} that are pairs of a field and its value.
     * For example,
     * <pre>
     *   setFeilds(Calendar.YEAR, 2013,
     *             Calendar.MONTH, Calendar.DECEMBER,
     *             Calendar.DAY_OF_MONTH, 23);</pre>
     * is equivalent to the sequence of the following
     * {@link #set(int, int) set} calls:
     * <pre>
     *   set(Calendar.YEAR, 2013)
     *   .set(Calendar.MONTH, Calendar.DECEMBER)
     *   .set(Calendar.DAY_OF_MONTH, 23);</pre>
     *
     * @param fieldValuePairs field-value pairs
     * @return this {@code Calendar.Builder}
     * @throws NullPointerException if {@code fieldValuePairs} is {@code null}
     * @throws IllegalArgumentException if any of fields are invalid, or if {@code
     * fieldValuePairs.length} is an odd number.
     * @throws IllegalStateException if the instant value has been set, or if fields have been set
     * too many (approximately {@link Integer#MAX_VALUE}) times.
     */
    public Builder setFields(int... fieldValuePairs) {
      int len = fieldValuePairs.length;
      if ((len % 2) != 0) {
        throw new IllegalArgumentException();
      }
      if (isInstantSet()) {
        throw new IllegalStateException("instant has been set");
      }
      if ((nextStamp + len / 2) < 0) {
        throw new IllegalStateException("stamp counter overflow");
      }
      allocateFields();
      for (int i = 0; i < len; ) {
        int field = fieldValuePairs[i++];
        // Note: WEEK_YEAR can't be set with this method.
        if (field < 0 || field >= FIELD_COUNT) {
          throw new IllegalArgumentException("field is invalid");
        }
        internalSet(field, fieldValuePairs[i++]);
      }
      return this;
    }

    /**
     * Sets the date field parameters to the values given by {@code year},
     * {@code month}, and {@code dayOfMonth}. This method is equivalent to
     * a call to:
     * <pre>
     *   setFields(Calendar.YEAR, year,
     *             Calendar.MONTH, month,
     *             Calendar.DAY_OF_MONTH, dayOfMonth);</pre>
     *
     * @param year the {@link Calendar#YEAR YEAR} value
     * @param month the {@link Calendar#MONTH MONTH} value (the month numbering is
     * <em>0-based</em>).
     * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value
     * @return this {@code Calendar.Builder}
     */
    public Builder setDate(int year, int month, int dayOfMonth) {
      return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth);
    }

    /**
     * Sets the time of day field parameters to the values given by
     * {@code hourOfDay}, {@code minute}, and {@code second}. This method is
     * equivalent to a call to:
     * <pre>
     *   setTimeOfDay(hourOfDay, minute, second, 0);</pre>
     *
     * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value (24-hour clock)
     * @param minute the {@link Calendar#MINUTE MINUTE} value
     * @param second the {@link Calendar#SECOND SECOND} value
     * @return this {@code Calendar.Builder}
     */
    public Builder setTimeOfDay(int hourOfDay, int minute, int second) {
      return setTimeOfDay(hourOfDay, minute, second, 0);
    }

    /**
     * Sets the time of day field parameters to the values given by
     * {@code hourOfDay}, {@code minute}, {@code second}, and
     * {@code millis}. This method is equivalent to a call to:
     * <pre>
     *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
     *             Calendar.MINUTE, minute,
     *             Calendar.SECOND, second,
     *             Calendar.MILLISECOND, millis);</pre>
     *
     * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value (24-hour clock)
     * @param minute the {@link Calendar#MINUTE MINUTE} value
     * @param second the {@link Calendar#SECOND SECOND} value
     * @param millis the {@link Calendar#MILLISECOND MILLISECOND} value
     * @return this {@code Calendar.Builder}
     */
    public Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) {
      return setFields(HOUR_OF_DAY, hourOfDay, MINUTE, minute,
          SECOND, second, MILLISECOND, millis);
    }

    /**
     * Sets the week-based date parameters to the values with the given
     * date specifiers - week year, week of year, and day of week.
     *
     * <p>If the specified calendar doesn't support week dates, the
     * {@link #build() build} method will throw an {@link IllegalArgumentException}.
     *
     * @param weekYear the week year
     * @param weekOfYear the week number based on {@code weekYear}
     * @param dayOfWeek the day of week value: one of the constants for the {@link
     * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field: {@link Calendar#SUNDAY SUNDAY}, ..., {@link
     * Calendar#SATURDAY SATURDAY}.
     * @return this {@code Calendar.Builder}
     * @see Calendar#setWeekDate(int, int, int)
     * @see Calendar#isWeekDateSupported()
     */
    public Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
      allocateFields();
      internalSet(WEEK_YEAR, weekYear);
      internalSet(WEEK_OF_YEAR, weekOfYear);
      internalSet(DAY_OF_WEEK, dayOfWeek);
      return this;
    }

    /**
     * Sets the time zone parameter to the given {@code zone}. If no time
     * zone parameter is given to this {@code Caledar.Builder}, the
     * {@linkplain TimeZone#getDefault() default
     * <code>TimeZone</code>} will be used in the {@link #build() build}
     * method.
     *
     * @param zone the {@link TimeZone}
     * @return this {@code Calendar.Builder}
     * @throws NullPointerException if {@code zone} is {@code null}
     * @see Calendar#setTimeZone(TimeZone)
     */
    public Builder setTimeZone(TimeZone zone) {
      if (zone == null) {
        throw new NullPointerException();
      }
      this.zone = zone;
      return this;
    }

    /**
     * Sets the lenient mode parameter to the value given by {@code lenient}.
     * If no lenient parameter is given to this {@code Calendar.Builder},
     * lenient mode will be used in the {@link #build() build} method.
     *
     * @param lenient {@code true} for lenient mode; {@code false} for non-lenient mode
     * @return this {@code Calendar.Builder}
     * @see Calendar#setLenient(boolean)
     */
    public Builder setLenient(boolean lenient) {
      this.lenient = lenient;
      return this;
    }

    /**
     * Sets the calendar type parameter to the given {@code type}. The
     * calendar type given by this method has precedence over any explicit
     * or implicit calendar type given by the
     * {@linkplain #setLocale(Locale) locale}.
     *
     * <p>In addition to the available calendar types returned by the
     * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes}
     * method, {@code "gregorian"} and {@code "iso8601"} as aliases of
     * {@code "gregory"} can be used with this method.
     *
     * @param type the calendar type
     * @return this {@code Calendar.Builder}
     * @throws NullPointerException if {@code type} is {@code null}
     * @throws IllegalArgumentException if {@code type} is unknown
     * @throws IllegalStateException if another calendar type has already been set
     * @see Calendar#getCalendarType()
     * @see Calendar#getAvailableCalendarTypes()
     */
    public Builder setCalendarType(String type) {
      if (type.equals("gregorian")) { // NPE if type == null
        type = "gregory";
      }
      if (!Calendar.getAvailableCalendarTypes().contains(type)
          && !type.equals("iso8601")) {
        throw new IllegalArgumentException("unknown calendar type: " + type);
      }
      if (this.type == null) {
        this.type = type;
      } else {
        if (!this.type.equals(type)) {
          throw new IllegalStateException("calendar type override");
        }
      }
      return this;
    }

    /**
     * Sets the locale parameter to the given {@code locale}. If no locale
     * is given to this {@code Calendar.Builder}, the {@linkplain
     * Locale#getDefault(Locale.Category) default <code>Locale</code>}
     * for {@link Locale.Category#FORMAT} will be used.
     *
     * <p>If no calendar type is explicitly given by a call to the
     * {@link #setCalendarType(String) setCalendarType} method,
     * the {@code Locale} value is used to determine what type of
     * {@code Calendar} to be built.
     *
     * <p>If no week definition parameters are explicitly given by a call to
     * the {@link #setWeekDefinition(int, int) setWeekDefinition} method, the
     * {@code Locale}'s default values are used.
     *
     * @param locale the {@link Locale}
     * @return this {@code Calendar.Builder}
     * @throws NullPointerException if {@code locale} is {@code null}
     * @see Calendar#getInstance(Locale)
     */
    public Builder setLocale(Locale locale) {
      if (locale == null) {
        throw new NullPointerException();
      }
      this.locale = locale;
      return this;
    }

    /**
     * Sets the week definition parameters to the values given by
     * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
     * used to determine the <a href="Calendar.html#First_Week">first
     * week</a> of a year. The parameters given by this method have
     * precedence over the default values given by the
     * {@linkplain #setLocale(Locale) locale}.
     *
     * @param firstDayOfWeek the first day of a week; one of {@link Calendar#SUNDAY} to {@link
     * Calendar#SATURDAY}
     * @param minimalDaysInFirstWeek the minimal number of days in the first week (1..7)
     * @return this {@code Calendar.Builder}
     * @throws IllegalArgumentException if {@code firstDayOfWeek} or {@code minimalDaysInFirstWeek}
     * is invalid
     * @see Calendar#getFirstDayOfWeek()
     * @see Calendar#getMinimalDaysInFirstWeek()
     */
    public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) {
      if (!isValidWeekParameter(firstDayOfWeek)
          || !isValidWeekParameter(minimalDaysInFirstWeek)) {
        throw new IllegalArgumentException();
      }
      this.firstDayOfWeek = firstDayOfWeek;
      this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
      return this;
    }

    /**
     * Returns a {@code Calendar} built from the parameters set by the
     * setter methods. The calendar type given by the {@link #setCalendarType(String)
     * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is
     * used to determine what {@code Calendar} to be created. If no explicit
     * calendar type is given, the locale's default calendar is created.
     *
     * <p>If the calendar type is {@code "iso8601"}, the
     * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date}
     * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)}
     * to be the <em>proleptic</em> Gregorian calendar. Its week definition
     * parameters are also set to be <a
     * href="GregorianCalendar.html#iso8601_compatible_setting">compatible
     * with the ISO 8601 standard</a>. Note that the
     * {@link GregorianCalendar#getCalendarType() getCalendarType} method of
     * a {@code GregorianCalendar} created with {@code "iso8601"} returns
     * {@code "gregory"}.
     *
     * <p>The default values are used for locale and time zone if these
     * parameters haven't been given explicitly.
     *
     * <p>Any out of range field values are either normalized in lenient
     * mode or detected as an invalid value in non-lenient mode.
     *
     * @return a {@code Calendar} built with parameters of this {@code Calendar.Builder}
     * @throws IllegalArgumentException if the calendar type is unknown, or if any invalid field
     * values are given in non-lenient mode, or if a week date is given for the calendar type that
     * doesn't support week dates.
     * @see Calendar#getInstance(TimeZone, Locale)
     * @see Locale#getDefault(Locale.Category)
     * @see TimeZone#getDefault()
     */
    public Calendar build() {
      if (locale == null) {
        locale = Locale.getDefault();
      }
      if (zone == null) {
        zone = TimeZone.getDefault();
      }
      Calendar cal;
      if (type == null) {
        type = locale.getUnicodeLocaleType("ca");
      }
      if (type == null) {
        if (locale.getCountry() == "TH"
            && locale.getLanguage() == "th") {
          type = "buddhist";
        } else {
          type = "gregory";
        }
      }
      switch (type) {
        case "gregory":
          cal = new GregorianCalendar(zone, locale, true);
          break;
        case "iso8601":
          GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
          // make gcal a proleptic Gregorian
          gcal.setGregorianChange(new Date(Long.MIN_VALUE));
          // and week definition to be compatible with ISO 8601
          setWeekDefinition(MONDAY, 4);
          cal = gcal;
          break;
        case "buddhist":
          cal = new BuddhistCalendar(zone, locale);
          cal.clear();
          break;
        case "japanese":
          cal = new JapaneseImperialCalendar(zone, locale, true);
          break;
        default:
          throw new IllegalArgumentException("unknown calendar type: " + type);
      }
      cal.setLenient(lenient);
      if (firstDayOfWeek != 0) {
        cal.setFirstDayOfWeek(firstDayOfWeek);
        cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
      }
      if (isInstantSet()) {
        cal.setTimeInMillis(instant);
        cal.complete();
        return cal;
      }

      if (fields != null) {
        boolean weekDate = isSet(WEEK_YEAR)
            && fields[WEEK_YEAR] > fields[YEAR];
        if (weekDate && !cal.isWeekDateSupported()) {
          throw new IllegalArgumentException("week date is unsupported by " + type);
        }

        // Set the fields from the min stamp to the max stamp so that
        // the fields resolution works in the Calendar.
        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
          for (int index = 0; index <= maxFieldIndex; index++) {
            if (fields[index] == stamp) {
              cal.set(index, fields[NFIELDS + index]);
              break;
            }
          }
        }

        if (weekDate) {
          int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
          int dayOfWeek = isSet(DAY_OF_WEEK)
              ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
          cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
        }
        cal.complete();
      }

      return cal;
    }

    private void allocateFields() {
      if (fields == null) {
        fields = new int[NFIELDS * 2];
        nextStamp = MINIMUM_USER_STAMP;
        maxFieldIndex = -1;
      }
    }

    private void internalSet(int field, int value) {
      fields[field] = nextStamp++;
      if (nextStamp < 0) {
        throw new IllegalStateException("stamp counter overflow");
      }
      fields[NFIELDS + field] = value;
      if (field > maxFieldIndex && field < WEEK_YEAR) {
        maxFieldIndex = field;
      }
    }

    private boolean isInstantSet() {
      return nextStamp == COMPUTED;
    }

    private boolean isSet(int index) {
      return fields != null && fields[index] > UNSET;
    }

    private boolean isValidWeekParameter(int value) {
      return value > 0 && value <= 7;
    }
  }

  /**
   * Constructs a Calendar with the default time zone
   * and the default {@link java.util.Locale.Category#FORMAT FORMAT}
   * locale.
   *
   * @see TimeZone#getDefault
   */
  protected Calendar() {
    this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
    sharedZone = true;
  }

  /**
   * Constructs a calendar with the specified time zone and locale.
   *
   * @param zone the time zone to use
   * @param aLocale the locale for the week data
   */
  protected Calendar(TimeZone zone, Locale aLocale) {
    fields = new int[FIELD_COUNT];
    isSet = new boolean[FIELD_COUNT];
    stamp = new int[FIELD_COUNT];

    this.zone = zone;
    setWeekCountData(aLocale);
  }

  /**
   * Gets a calendar using the default time zone and locale. The
   * <code>Calendar</code> returned is based on the current time
   * in the default time zone with the default
   * {@link Locale.Category#FORMAT FORMAT} locale.
   *
   * @return a Calendar.
   */
  public static Calendar getInstance() {
    return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
  }

  /**
   * Gets a calendar using the specified time zone and default locale.
   * The <code>Calendar</code> returned is based on the current time
   * in the given time zone with the default
   * {@link Locale.Category#FORMAT FORMAT} locale.
   *
   * @param zone the time zone to use
   * @return a Calendar.
   */
  public static Calendar getInstance(TimeZone zone) {
    return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
  }

  /**
   * Gets a calendar using the default time zone and specified locale.
   * The <code>Calendar</code> returned is based on the current time
   * in the default time zone with the given locale.
   *
   * @param aLocale the locale for the week data
   * @return a Calendar.
   */
  public static Calendar getInstance(Locale aLocale) {
    return createCalendar(TimeZone.getDefault(), aLocale);
  }

  /**
   * Gets a calendar with the specified time zone and locale.
   * The <code>Calendar</code> returned is based on the current time
   * in the given time zone with the given locale.
   *
   * @param zone the time zone to use
   * @param aLocale the locale for the week data
   * @return a Calendar.
   */
  public static Calendar getInstance(TimeZone zone,
      Locale aLocale) {
    return createCalendar(zone, aLocale);
  }

  private static Calendar createCalendar(TimeZone zone,
      Locale aLocale) {
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
            .getCalendarProvider();
    if (provider != null) {
      try {
        return provider.getInstance(zone, aLocale);
      } catch (IllegalArgumentException iae) {
        // fall back to the default instantiation
      }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
      String caltype = aLocale.getUnicodeLocaleType("ca");
      if (caltype != null) {
        switch (caltype) {
          case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
            break;
          case "japanese":
            cal = new JapaneseImperialCalendar(zone, aLocale);
            break;
          case "gregory":
            cal = new GregorianCalendar(zone, aLocale);
            break;
        }
      }
    }
    if (cal == null) {
      // If no known calendar type is explicitly specified,
      // perform the traditional way to create a Calendar:
      // create a BuddhistCalendar for th_TH locale,
      // a JapaneseImperialCalendar for ja_JP_JP locale, or
      // a GregorianCalendar for any other locales.
      // NOTE: The language, country and variant strings are interned.
      if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
        cal = new BuddhistCalendar(zone, aLocale);
      } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
          && aLocale.getCountry() == "JP") {
        cal = new JapaneseImperialCalendar(zone, aLocale);
      } else {
        cal = new GregorianCalendar(zone, aLocale);
      }
    }
    return cal;
  }

  /**
   * Returns an array of all locales for which the <code>getInstance</code>
   * methods of this class can return localized instances.
   * The array returned must contain at least a <code>Locale</code>
   * instance equal to {@link java.util.Locale#US Locale.US}.
   *
   * @return An array of locales for which localized <code>Calendar</code> instances are available.
   */
  public static synchronized Locale[] getAvailableLocales() {
    return DateFormat.getAvailableLocales();
  }

  /**
   * Converts the current calendar field values in {@link #fields fields[]}
   * to the millisecond time value
   * {@link #time}.
   *
   * @see #complete()
   * @see #computeFields()
   */
  protected abstract void computeTime();

  /**
   * Converts the current millisecond time value {@link #time}
   * to calendar field values in {@link #fields fields[]}.
   * This allows you to sync up the calendar field values with
   * a new time that is set for the calendar.  The time is <em>not</em>
   * recomputed first; to recompute the time, then the fields, call the
   * {@link #complete()} method.
   *
   * @see #computeTime()
   */
  protected abstract void computeFields();

  /**
   * Returns a <code>Date</code> object representing this
   * <code>Calendar</code>'s time value (millisecond offset from the <a
   * href="#Epoch">Epoch</a>").
   *
   * @return a <code>Date</code> representing the time value.
   * @see #setTime(Date)
   * @see #getTimeInMillis()
   */
  public final Date getTime() {
    return new Date(getTimeInMillis());
  }

  /**
   * Sets this Calendar's time with the given <code>Date</code>.
   * <p>
   * Note: Calling <code>setTime()</code> with
   * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
   * may yield incorrect field values from <code>get()</code>.
   *
   * @param date the given Date.
   * @see #getTime()
   * @see #setTimeInMillis(long)
   */
  public final void setTime(Date date) {
    setTimeInMillis(date.getTime());
  }

  /**
   * Returns this Calendar's time value in milliseconds.
   *
   * @return the current time as UTC milliseconds from the epoch.
   * @see #getTime()
   * @see #setTimeInMillis(long)
   */
  public long getTimeInMillis() {
    if (!isTimeSet) {
      updateTime();
    }
    return time;
  }

  /**
   * Sets this Calendar's current time from the given long value.
   *
   * @param millis the new time in UTC milliseconds from the epoch.
   * @see #setTime(Date)
   * @see #getTimeInMillis()
   */
  public void setTimeInMillis(long millis) {
    // If we don't need to recalculate the calendar field values,
    // do nothing.
    if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
        && (zone instanceof ZoneInfo) && !((ZoneInfo) zone).isDirty()) {
      return;
    }
    time = millis;
    isTimeSet = true;
    areFieldsSet = false;
    computeFields();
    areAllFieldsSet = areFieldsSet = true;
  }

  /**
   * Returns the value of the given calendar field. In lenient mode,
   * all calendar fields are normalized. In non-lenient mode, all
   * calendar fields are validated and this method throws an
   * exception if any calendar fields have out-of-range values. The
   * normalization and validation are handled by the
   * {@link #complete()} method, which process is calendar
   * system dependent.
   *
   * @param field the given calendar field.
   * @return the value for the given calendar field.
   * @throws ArrayIndexOutOfBoundsException if the specified field is out of range (<code>field &lt;
   * 0 || field &gt;= FIELD_COUNT</code>).
   * @see #set(int, int)
   * @see #complete()
   */
  public int get(int field) {
    complete();
    return internalGet(field);
  }

  /**
   * Returns the value of the given calendar field. This method does
   * not involve normalization or validation of the field value.
   *
   * @param field the given calendar field.
   * @return the value for the given calendar field.
   * @see #get(int)
   */
  protected final int internalGet(int field) {
    return fields[field];
  }

  /**
   * Sets the value of the given calendar field. This method does
   * not affect any setting state of the field in this
   * <code>Calendar</code> instance.
   *
   * @throws IndexOutOfBoundsException if the specified field is out of range (<code>field &lt; 0 ||
   * field &gt;= FIELD_COUNT</code>).
   * @see #areFieldsSet
   * @see #isTimeSet
   * @see #areAllFieldsSet
   * @see #set(int, int)
   */
  final void internalSet(int field, int value) {
    fields[field] = value;
  }

  /**
   * Sets the given calendar field to the given value. The value is not
   * interpreted by this method regardless of the leniency mode.
   *
   * @param field the given calendar field.
   * @param value the value to be set for the given calendar field.
   * @throws ArrayIndexOutOfBoundsException if the specified field is out of range (<code>field &lt;
   * 0 || field &gt;= FIELD_COUNT</code>). in non-lenient mode.
   * @see #set(int, int, int)
   * @see #set(int, int, int, int, int)
   * @see #set(int, int, int, int, int, int)
   * @see #get(int)
   */
  public void set(int field, int value) {
    // If the fields are partially normalized, calculate all the
    // fields before changing any fields.
    if (areFieldsSet && !areAllFieldsSet) {
      computeFields();
    }
    internalSet(field, value);
    isTimeSet = false;
    areFieldsSet = false;
    isSet[field] = true;
    stamp[field] = nextStamp++;
    if (nextStamp == Integer.MAX_VALUE) {
      adjustStamp();
    }
  }

  /**
   * Sets the values for the calendar fields <code>YEAR</code>,
   * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
   * Previous values of other calendar fields are retained.  If this is not desired,
   * call {@link #clear()} first.
   *
   * @param year the value used to set the <code>YEAR</code> calendar field.
   * @param month the value used to set the <code>MONTH</code> calendar field. Month value is
   * 0-based. e.g., 0 for January.
   * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
   * @see #set(int, int)
   * @see #set(int, int, int, int, int)
   * @see #set(int, int, int, int, int, int)
   */
  public final void set(int year, int month, int date) {
    set(YEAR, year);
    set(MONTH, month);
    set(DATE, date);
  }

  /**
   * Sets the values for the calendar fields <code>YEAR</code>,
   * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
   * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
   * Previous values of other fields are retained.  If this is not desired,
   * call {@link #clear()} first.
   *
   * @param year the value used to set the <code>YEAR</code> calendar field.
   * @param month the value used to set the <code>MONTH</code> calendar field. Month value is
   * 0-based. e.g., 0 for January.
   * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
   * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
   * @param minute the value used to set the <code>MINUTE</code> calendar field.
   * @see #set(int, int)
   * @see #set(int, int, int)
   * @see #set(int, int, int, int, int, int)
   */
  public final void set(int year, int month, int date, int hourOfDay, int minute) {
    set(YEAR, year);
    set(MONTH, month);
    set(DATE, date);
    set(HOUR_OF_DAY, hourOfDay);
    set(MINUTE, minute);
  }

  /**
   * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
   * <code>DAY_OF_MONTH</code>, <code>HOUR_OF_DAY</code>, <code>MINUTE</code>, and
   * <code>SECOND</code>.
   * Previous values of other fields are retained.  If this is not desired,
   * call {@link #clear()} first.
   *
   * @param year the value used to set the <code>YEAR</code> calendar field.
   * @param month the value used to set the <code>MONTH</code> calendar field. Month value is
   * 0-based. e.g., 0 for January.
   * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
   * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
   * @param minute the value used to set the <code>MINUTE</code> calendar field.
   * @param second the value used to set the <code>SECOND</code> calendar field.
   * @see #set(int, int)
   * @see #set(int, int, int)
   * @see #set(int, int, int, int, int)
   */
  public final void set(int year, int month, int date, int hourOfDay, int minute,
      int second) {
    set(YEAR, year);
    set(MONTH, month);
    set(DATE, date);
    set(HOUR_OF_DAY, hourOfDay);
    set(MINUTE, minute);
    set(SECOND, second);
  }

  /**
   * Sets all the calendar field values and the time value
   * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
   * this <code>Calendar</code> undefined. This means that {@link
   * #isSet(int) isSet()} will return <code>false</code> for all the
   * calendar fields, and the date and time calculations will treat
   * the fields as if they had never been set. A
   * <code>Calendar</code> implementation class may use its specific
   * default field values for date/time calculations. For example,
   * <code>GregorianCalendar</code> uses 1970 if the
   * <code>YEAR</code> field value is undefined.
   *
   * @see #clear(int)
   */
  public final void clear() {
    for (int i = 0; i < fields.length; ) {
      stamp[i] = fields[i] = 0; // UNSET == 0
      isSet[i++] = false;
    }
    areAllFieldsSet = areFieldsSet = false;
    isTimeSet = false;
  }

  /**
   * Sets the given calendar field value and the time value
   * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
   * this <code>Calendar</code> undefined. This means that {@link
   * #isSet(int) isSet(field)} will return <code>false</code>, and
   * the date and time calculations will treat the field as if it
   * had never been set. A <code>Calendar</code> implementation
   * class may use the field's specific default value for date and
   * time calculations.
   *
   * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
   * fields are handled independently and the <a
   * href="#time_resolution">the resolution rule for the time of
   * day</a> is applied. Clearing one of the fields doesn't reset
   * the hour of day value of this <code>Calendar</code>. Use {@link
   * #set(int, int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
   * value.
   *
   * @param field the calendar field to be cleared.
   * @see #clear()
   */
  public final void clear(int field) {
    fields[field] = 0;
    stamp[field] = UNSET;
    isSet[field] = false;

    areAllFieldsSet = areFieldsSet = false;
    isTimeSet = false;
  }

  /**
   * Determines if the given calendar field has a value set,
   * including cases that the value has been set by internal fields
   * calculations triggered by a <code>get</code> method call.
   *
   * @param field the calendar field to test
   * @return <code>true</code> if the given calendar field has a value set; <code>false</code>
   * otherwise.
   */
  public final boolean isSet(int field) {
    return stamp[field] != UNSET;
  }

  /**
   * Returns the string representation of the calendar
   * <code>field</code> value in the given <code>style</code> and
   * <code>locale</code>.  If no string representation is
   * applicable, <code>null</code> is returned. This method calls
   * {@link Calendar#get(int) get(field)} to get the calendar
   * <code>field</code> value if the string representation is
   * applicable to the given calendar <code>field</code>.
   *
   * <p>For example, if this <code>Calendar</code> is a
   * <code>GregorianCalendar</code> and its date is 2005-01-01, then
   * the string representation of the {@link #MONTH} field would be
   * "January" in the long style in an English locale or "Jan" in
   * the short style. However, no string representation would be
   * available for the {@link #DAY_OF_MONTH} field, and this method
   * would return <code>null</code>.
   *
   * <p>The default implementation supports the calendar fields for
   * which a {@link DateFormatSymbols} has names in the given
   * <code>locale</code>.
   *
   * @param field the calendar field for which the string representation is returned
   * @param style the style applied to the string representation; one of {@link #SHORT_FORMAT}
   * ({@link #SHORT}), {@link #SHORT_STANDALONE}, {@link #LONG_FORMAT} ({@link #LONG}), {@link
   * #LONG_STANDALONE}, {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}.
   * @param locale the locale for the string representation (any calendar types specified by {@code
   * locale} are ignored)
   * @return the string representation of the given {@code field} in the given {@code style}, or
   * {@code null} if no string representation is applicable.
   * @throws IllegalArgumentException if {@code field} or {@code style} is invalid, or if this
   * {@code Calendar} is non-lenient and any of the calendar fields have invalid values
   * @throws NullPointerException if {@code locale} is null
   * @since 1.6
   */
  public String getDisplayName(int field, int style, Locale locale) {
    if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
        ERA_MASK | MONTH_MASK | DAY_OF_WEEK_MASK | AM_PM_MASK)) {
      return null;
    }

    String calendarType = getCalendarType();
    int fieldValue = get(field);
    // the standalone and narrow styles are supported only through CalendarDataProviders.
    if (isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
      String val = CalendarDataUtility.retrieveFieldValueName(calendarType,
          field, fieldValue,
          style, locale);
      // Perform fallback here to follow the CLDR rules
      if (val == null) {
        if (isNarrowFormatStyle(style)) {
          val = CalendarDataUtility.retrieveFieldValueName(calendarType,
              field, fieldValue,
              toStandaloneStyle(style),
              locale);
        } else if (isStandaloneStyle(style)) {
          val = CalendarDataUtility.retrieveFieldValueName(calendarType,
              field, fieldValue,
              getBaseStyle(style),
              locale);
        }
      }
      return val;
    }

    DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
    String[] strings = getFieldStrings(field, style, symbols);
    if (strings != null) {
      if (fieldValue < strings.length) {
        return strings[fieldValue];
      }
    }
    return null;
  }

  /**
   * Returns a {@code Map} containing all names of the calendar
   * {@code field} in the given {@code style} and
   * {@code locale} and their corresponding field values. For
   * example, if this {@code Calendar} is a {@link
   * GregorianCalendar}, the returned map would contain "Jan" to
   * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
   * {@linkplain #SHORT short} style in an English locale.
   *
   * <p>Narrow names may not be unique due to use of single characters,
   * such as "S" for Sunday and Saturday. In that case narrow names are not
   * included in the returned {@code Map}.
   *
   * <p>The values of other calendar fields may be taken into
   * account to determine a set of display names. For example, if
   * this {@code Calendar} is a lunisolar calendar system and
   * the year value given by the {@link #YEAR} field has a leap
   * month, this method would return month names containing the leap
   * month name, and month names are mapped to their values specific
   * for the year.
   *
   * <p>The default implementation supports display names contained in
   * a {@link DateFormatSymbols}. For example, if {@code field}
   * is {@link #MONTH} and {@code style} is {@link
   * #ALL_STYLES}, this method returns a {@code Map} containing
   * all strings returned by {@link DateFormatSymbols#getShortMonths()}
   * and {@link DateFormatSymbols#getMonths()}.
   *
   * @param field the calendar field for which the display names are returned
   * @param style the style applied to the string representation; one of {@link #SHORT_FORMAT}
   * ({@link #SHORT}), {@link #SHORT_STANDALONE}, {@link #LONG_FORMAT} ({@link #LONG}), {@link
   * #LONG_STANDALONE}, {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}
   * @param locale the locale for the display names
   * @return a {@code Map} containing all display names in {@code style} and {@code locale} and
   * their field values, or {@code null} if no display names are defined for {@code field}
   * @throws IllegalArgumentException if {@code field} or {@code style} is invalid, or if this
   * {@code Calendar} is non-lenient and any of the calendar fields have invalid values
   * @throws NullPointerException if {@code locale} is null
   * @since 1.6
   */
  public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
    if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
        ERA_MASK | MONTH_MASK | DAY_OF_WEEK_MASK | AM_PM_MASK)) {
      return null;
    }

    String calendarType = getCalendarType();
    if (style == ALL_STYLES || isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
      Map<String, Integer> map;
      map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field, style, locale);

      // Perform fallback here to follow the CLDR rules
      if (map == null) {
        if (isNarrowFormatStyle(style)) {
          map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
              toStandaloneStyle(style), locale);
        } else if (style != ALL_STYLES) {
          map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
              getBaseStyle(style), locale);
        }
      }
      return map;
    }

    // SHORT or LONG
    return getDisplayNamesImpl(field, style, locale);
  }

  private Map<String, Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
    DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
    String[] strings = getFieldStrings(field, style, symbols);
    if (strings != null) {
      Map<String, Integer> names = new HashMap<>();
      for (int i = 0; i < strings.length; i++) {
        if (strings[i].length() == 0) {
          continue;
        }
        names.put(strings[i], i);
      }
      return names;
    }
    return null;
  }

  boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
      Locale locale, int fieldMask) {
    int baseStyle = getBaseStyle(style); // Ignore the standalone mask
    if (field < 0 || field >= fields.length ||
        baseStyle < minStyle || baseStyle > maxStyle) {
      throw new IllegalArgumentException();
    }
    if (locale == null) {
      throw new NullPointerException();
    }
    return isFieldSet(fieldMask, field);
  }

  private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
    int baseStyle = getBaseStyle(style); // ignore the standalone mask

    // DateFormatSymbols doesn't support any narrow names.
    if (baseStyle == NARROW_FORMAT) {
      return null;
    }

    String[] strings = null;
    switch (field) {
      case ERA:
        strings = symbols.getEras();
        break;

      case MONTH:
        strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
        break;

      case DAY_OF_WEEK:
        strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
        break;

      case AM_PM:
        strings = symbols.getAmPmStrings();
        break;
    }
    return strings;
  }

  /**
   * Fills in any unset fields in the calendar fields. First, the {@link
   * #computeTime()} method is called if the time value (millisecond offset
   * from the <a href="#Epoch">Epoch</a>) has not been calculated from
   * calendar field values. Then, the {@link #computeFields()} method is
   * called to calculate all calendar field values.
   */
  protected void complete() {
    if (!isTimeSet) {
      updateTime();
    }
    if (!areFieldsSet || !areAllFieldsSet) {
      computeFields(); // fills in unset fields
      areAllFieldsSet = areFieldsSet = true;
    }
  }

  /**
   * Returns whether the value of the specified calendar field has been set
   * externally by calling one of the setter methods rather than by the
   * internal time calculation.
   *
   * @return <code>true</code> if the field has been set externally, <code>false</code> otherwise.
   * @throws IndexOutOfBoundsException if the specified <code>field</code> is out of range
   * (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
   * @see #selectFields()
   * @see #setFieldsComputed(int)
   */
  final boolean isExternallySet(int field) {
    return stamp[field] >= MINIMUM_USER_STAMP;
  }

  /**
   * Returns a field mask (bit mask) indicating all calendar fields that
   * have the state of externally or internally set.
   *
   * @return a bit mask indicating set state fields
   */
  final int getSetStateFields() {
    int mask = 0;
    for (int i = 0; i < fields.length; i++) {
      if (stamp[i] != UNSET) {
        mask |= 1 << i;
      }
    }
    return mask;
  }

  /**
   * Sets the state of the specified calendar fields to
   * <em>computed</em>. This state means that the specified calendar fields
   * have valid values that have been set by internal time calculation
   * rather than by calling one of the setter methods.
   *
   * @param fieldMask the field to be marked as computed.
   * @throws IndexOutOfBoundsException if the specified <code>field</code> is out of range
   * (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
   * @see #isExternallySet(int)
   * @see #selectFields()
   */
  final void setFieldsComputed(int fieldMask) {
    if (fieldMask == ALL_FIELDS) {
      for (int i = 0; i < fields.length; i++) {
        stamp[i] = COMPUTED;
        isSet[i] = true;
      }
      areFieldsSet = areAllFieldsSet = true;
    } else {
      for (int i = 0; i < fields.length; i++) {
        if ((fieldMask & 1) == 1) {
          stamp[i] = COMPUTED;
          isSet[i] = true;
        } else {
          if (areAllFieldsSet && !isSet[i]) {
            areAllFieldsSet = false;
          }
        }
        fieldMask >>>= 1;
      }
    }
  }

  /**
   * Sets the state of the calendar fields that are <em>not</em> specified
   * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
   * specifies all the calendar fields, then the state of this
   * <code>Calendar</code> becomes that all the calendar fields are in sync
   * with the time value (millisecond offset from the Epoch).
   *
   * @param fieldMask the field mask indicating which calendar fields are in sync with the time
   * value.
   * @throws IndexOutOfBoundsException if the specified <code>field</code> is out of range
   * (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
   * @see #isExternallySet(int)
   * @see #selectFields()
   */
  final void setFieldsNormalized(int fieldMask) {
    if (fieldMask != ALL_FIELDS) {
      for (int i = 0; i < fields.length; i++) {
        if ((fieldMask & 1) == 0) {
          stamp[i] = fields[i] = 0; // UNSET == 0
          isSet[i] = false;
        }
        fieldMask >>= 1;
      }
    }

    // Some or all of the fields are in sync with the
    // milliseconds, but the stamp values are not normalized yet.
    areFieldsSet = true;
    areAllFieldsSet = false;
  }

  /**
   * Returns whether the calendar fields are partially in sync with the time
   * value or fully in sync but not stamp values are not normalized yet.
   */
  final boolean isPartiallyNormalized() {
    return areFieldsSet && !areAllFieldsSet;
  }

  /**
   * Returns whether the calendar fields are fully in sync with the time
   * value.
   */
  final boolean isFullyNormalized() {
    return areFieldsSet && areAllFieldsSet;
  }

  /**
   * Marks this Calendar as not sync'd.
   */
  final void setUnnormalized() {
    areFieldsSet = areAllFieldsSet = false;
  }

  /**
   * Returns whether the specified <code>field</code> is on in the
   * <code>fieldMask</code>.
   */
  static boolean isFieldSet(int fieldMask, int field) {
    return (fieldMask & (1 << field)) != 0;
  }

  /**
   * Returns a field mask indicating which calendar field values
   * to be used to calculate the time value. The calendar fields are
   * returned as a bit mask, each bit of which corresponds to a field, i.e.,
   * the mask value of <code>field</code> is <code>(1 &lt;&lt;
   * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
   * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
   * equal to
   * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
   *
   * <p>This method supports the calendar fields resolution as described in
   * the class description. If the bit mask for a given field is on and its
   * field has not been set (i.e., <code>isSet(field)</code> is
   * <code>false</code>), then the default value of the field has to be
   * used, which case means that the field has been selected because the
   * selected combination involves the field.
   *
   * @return a bit mask of selected fields
   * @see #isExternallySet(int)
   */
  final int selectFields() {
    // This implementation has been taken from the GregorianCalendar class.

    // The YEAR field must always be used regardless of its SET
    // state because YEAR is a mandatory field to determine the date
    // and the default value (EPOCH_YEAR) may change through the
    // normalization process.
    int fieldMask = YEAR_MASK;

    if (stamp[ERA] != UNSET) {
      fieldMask |= ERA_MASK;
    }
    // Find the most recent group of fields specifying the day within
    // the year.  These may be any of the following combinations:
    //   MONTH + DAY_OF_MONTH
    //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
    //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
    //   DAY_OF_YEAR
    //   WEEK_OF_YEAR + DAY_OF_WEEK
    // We look for the most recent of the fields in each group to determine
    // the age of the group.  For groups involving a week-related field such
    // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
    // week-related field and the DAY_OF_WEEK must be set for the group as a
    // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
    int dowStamp = stamp[DAY_OF_WEEK];
    int monthStamp = stamp[MONTH];
    int domStamp = stamp[DAY_OF_MONTH];
    int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
    int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
    int doyStamp = stamp[DAY_OF_YEAR];
    int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);

    int bestStamp = domStamp;
    if (womStamp > bestStamp) {
      bestStamp = womStamp;
    }
    if (dowimStamp > bestStamp) {
      bestStamp = dowimStamp;
    }
    if (doyStamp > bestStamp) {
      bestStamp = doyStamp;
    }
    if (woyStamp > bestStamp) {
      bestStamp = woyStamp;
    }

        /* No complete combination exists.  Look for WEEK_OF_MONTH,
         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
         * as DAY_OF_WEEK_IN_MONTH.
         */
    if (bestStamp == UNSET) {
      womStamp = stamp[WEEK_OF_MONTH];
      dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
      woyStamp = stamp[WEEK_OF_YEAR];
      bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);

            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
             * result in bestStamp = domStamp = UNSET if no fields are set,
             * which indicates DAY_OF_MONTH.
             */
      if (bestStamp == UNSET) {
        bestStamp = domStamp = monthStamp;
      }
    }

    if (bestStamp == domStamp ||
        (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
        (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
      fieldMask |= MONTH_MASK;
      if (bestStamp == domStamp) {
        fieldMask |= DAY_OF_MONTH_MASK;
      } else {
        assert (bestStamp == womStamp || bestStamp == dowimStamp);
        if (dowStamp != UNSET) {
          fieldMask |= DAY_OF_WEEK_MASK;
        }
        if (womStamp == dowimStamp) {
          // When they are equal, give the priority to
          // WEEK_OF_MONTH for compatibility.
          if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
            fieldMask |= WEEK_OF_MONTH_MASK;
          } else {
            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
          }
        } else {
          if (bestStamp == womStamp) {
            fieldMask |= WEEK_OF_MONTH_MASK;
          } else {
            assert (bestStamp == dowimStamp);
            if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
              fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
            }
          }
        }
      }
    } else {
      assert (bestStamp == doyStamp || bestStamp == woyStamp ||
          bestStamp == UNSET);
      if (bestStamp == doyStamp) {
        fieldMask |= DAY_OF_YEAR_MASK;
      } else {
        assert (bestStamp == woyStamp);
        if (dowStamp != UNSET) {
          fieldMask |= DAY_OF_WEEK_MASK;
        }
        fieldMask |= WEEK_OF_YEAR_MASK;
      }
    }

    // Find the best set of fields specifying the time of day.  There
    // are only two possibilities here; the HOUR_OF_DAY or the
    // AM_PM and the HOUR.
    int hourOfDayStamp = stamp[HOUR_OF_DAY];
    int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
    bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;

    // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
    if (bestStamp == UNSET) {
      bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
    }

    // Hours
    if (bestStamp != UNSET) {
      if (bestStamp == hourOfDayStamp) {
        fieldMask |= HOUR_OF_DAY_MASK;
      } else {
        fieldMask |= HOUR_MASK;
        if (stamp[AM_PM] != UNSET) {
          fieldMask |= AM_PM_MASK;
        }
      }
    }
    if (stamp[MINUTE] != UNSET) {
      fieldMask |= MINUTE_MASK;
    }
    if (stamp[SECOND] != UNSET) {
      fieldMask |= SECOND_MASK;
    }
    if (stamp[MILLISECOND] != UNSET) {
      fieldMask |= MILLISECOND_MASK;
    }
    if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
      fieldMask |= ZONE_OFFSET_MASK;
    }
    if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
      fieldMask |= DST_OFFSET_MASK;
    }

    return fieldMask;
  }

  int getBaseStyle(int style) {
    return style & ~STANDALONE_MASK;
  }

  private int toStandaloneStyle(int style) {
    return style | STANDALONE_MASK;
  }

  private boolean isStandaloneStyle(int style) {
    return (style & STANDALONE_MASK) != 0;
  }

  private boolean isNarrowStyle(int style) {
    return style == NARROW_FORMAT || style == NARROW_STANDALONE;
  }

  private boolean isNarrowFormatStyle(int style) {
    return style == NARROW_FORMAT;
  }

  /**
   * Returns the pseudo-time-stamp for two fields, given their
   * individual pseudo-time-stamps.  If either of the fields
   * is unset, then the aggregate is unset.  Otherwise, the
   * aggregate is the later of the two stamps.
   */
  private static int aggregateStamp(int stamp_a, int stamp_b) {
    if (stamp_a == UNSET || stamp_b == UNSET) {
      return UNSET;
    }
    return (stamp_a > stamp_b) ? stamp_a : stamp_b;
  }

  /**
   * Returns an unmodifiable {@code Set} containing all calendar types
   * supported by {@code Calendar} in the runtime environment. The available
   * calendar types can be used for the <a
   * href="Locale.html#def_locale_extension">Unicode locale extensions</a>.
   * The {@code Set} returned contains at least {@code "gregory"}. The
   * calendar types don't include aliases, such as {@code "gregorian"} for
   * {@code "gregory"}.
   *
   * @return an unmodifiable {@code Set} containing all available calendar types
   * @see #getCalendarType()
   * @see Calendar.Builder#setCalendarType(String)
   * @see Locale#getUnicodeLocaleType(String)
   * @since 1.8
   */
  public static Set<String> getAvailableCalendarTypes() {
    return AvailableCalendarTypes.SET;
  }

  private static class AvailableCalendarTypes {

    private static final Set<String> SET;

    static {
      Set<String> set = new HashSet<>(3);
      set.add("gregory");
      set.add("buddhist");
      set.add("japanese");
      SET = Collections.unmodifiableSet(set);
    }

    private AvailableCalendarTypes() {
    }
  }

  /**
   * Returns the calendar type of this {@code Calendar}. Calendar types are
   * defined by the <em>Unicode Locale Data Markup Language (LDML)</em>
   * specification.
   *
   * <p>The default implementation of this method returns the class name of
   * this {@code Calendar} instance. Any subclasses that implement
   * LDML-defined calendar systems should override this method to return
   * appropriate calendar types.
   *
   * @return the LDML-defined calendar type or the class name of this {@code Calendar} instance
   * @see <a href="Locale.html#def_extensions">Locale extensions</a>
   * @see Locale.Builder#setLocale(Locale)
   * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
   * @since 1.8
   */
  public String getCalendarType() {
    return this.getClass().getName();
  }

  /**
   * Compares this <code>Calendar</code> to the specified
   * <code>Object</code>.  The result is <code>true</code> if and only if
   * the argument is a <code>Calendar</code> object of the same calendar
   * system that represents the same time value (millisecond offset from the
   * <a href="#Epoch">Epoch</a>) under the same
   * <code>Calendar</code> parameters as this object.
   *
   * <p>The <code>Calendar</code> parameters are the values represented
   * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
   * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
   * methods. If there is any difference in those parameters
   * between the two <code>Calendar</code>s, this method returns
   * <code>false</code>.
   *
   * <p>Use the {@link #compareTo(Calendar) compareTo} method to
   * compare only the time values.
   *
   * @param obj the object to compare with.
   * @return <code>true</code> if this object is equal to <code>obj</code>; <code>false</code>
   * otherwise.
   */
  @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    try {
      Calendar that = (Calendar) obj;
      return compareTo(getMillisOf(that)) == 0 &&
          lenient == that.lenient &&
          firstDayOfWeek == that.firstDayOfWeek &&
          minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
          zone.equals(that.zone);
    } catch (Exception e) {
      // Note: GregorianCalendar.computeTime throws
      // IllegalArgumentException if the ERA value is invalid
      // even it's in lenient mode.
    }
    return false;
  }

  /**
   * Returns a hash code for this calendar.
   *
   * @return a hash code value for this object.
   * @since 1.2
   */
  @Override
  public int hashCode() {
    // 'otheritems' represents the hash code for the previous versions.
    int otheritems = (lenient ? 1 : 0)
        | (firstDayOfWeek << 1)
        | (minimalDaysInFirstWeek << 4)
        | (zone.hashCode() << 7);
    long t = getMillisOf(this);
    return (int) t ^ (int) (t >> 32) ^ otheritems;
  }

  /**
   * Returns whether this <code>Calendar</code> represents a time
   * before the time represented by the specified
   * <code>Object</code>. This method is equivalent to:
   * <pre>{@code
   *         compareTo(when) < 0
   * }</pre>
   * if and only if <code>when</code> is a <code>Calendar</code>
   * instance. Otherwise, the method returns <code>false</code>.
   *
   * @param when the <code>Object</code> to be compared
   * @return <code>true</code> if the time of this <code>Calendar</code> is before the time
   * represented by <code>when</code>; <code>false</code> otherwise.
   * @see #compareTo(Calendar)
   */
  public boolean before(Object when) {
    return when instanceof Calendar
        && compareTo((Calendar) when) < 0;
  }

  /**
   * Returns whether this <code>Calendar</code> represents a time
   * after the time represented by the specified
   * <code>Object</code>. This method is equivalent to:
   * <pre>{@code
   *         compareTo(when) > 0
   * }</pre>
   * if and only if <code>when</code> is a <code>Calendar</code>
   * instance. Otherwise, the method returns <code>false</code>.
   *
   * @param when the <code>Object</code> to be compared
   * @return <code>true</code> if the time of this <code>Calendar</code> is after the time
   * represented by <code>when</code>; <code>false</code> otherwise.
   * @see #compareTo(Calendar)
   */
  public boolean after(Object when) {
    return when instanceof Calendar
        && compareTo((Calendar) when) > 0;
  }

  /**
   * Compares the time values (millisecond offsets from the <a
   * href="#Epoch">Epoch</a>) represented by two
   * <code>Calendar</code> objects.
   *
   * @param anotherCalendar the <code>Calendar</code> to be compared.
   * @return the value <code>0</code> if the time represented by the argument is equal to the time
   * represented by this <code>Calendar</code>; a value less than <code>0</code> if the time of this
   * <code>Calendar</code> is before the time represented by the argument; and a value greater than
   * <code>0</code> if the time of this <code>Calendar</code> is after the time represented by the
   * argument.
   * @throws NullPointerException if the specified <code>Calendar</code> is <code>null</code>.
   * @throws IllegalArgumentException if the time value of the specified <code>Calendar</code>
   * object can't be obtained due to any invalid calendar values.
   * @since 1.5
   */
  @Override
  public int compareTo(Calendar anotherCalendar) {
    return compareTo(getMillisOf(anotherCalendar));
  }

  /**
   * Adds or subtracts the specified amount of time to the given calendar field,
   * based on the calendar's rules. For example, to subtract 5 days from
   * the current time of the calendar, you can achieve it by calling:
   * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
   *
   * @param field the calendar field.
   * @param amount the amount of date or time to be added to the field.
   * @see #roll(int, int)
   * @see #set(int, int)
   */
  abstract public void add(int field, int amount);

  /**
   * Adds or subtracts (up/down) a single unit of time on the given time
   * field without changing larger fields. For example, to roll the current
   * date up by one day, you can achieve it by calling:
   * <p>roll(Calendar.DATE, true).
   * When rolling on the year or Calendar.YEAR field, it will roll the year
   * value in the range between 1 and the value returned by calling
   * <code>getMaximum(Calendar.YEAR)</code>.
   * When rolling on the month or Calendar.MONTH field, other fields like
   * date might conflict and, need to be changed. For instance,
   * rolling the month on the date 01/31/96 will result in 02/29/96.
   * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
   * roll the hour value in the range between 0 and 23, which is zero-based.
   *
   * @param field the time field.
   * @param up indicates if the value of the specified time field is to be rolled up or rolled down.
   * Use true if rolling up, false otherwise.
   * @see Calendar#add(int, int)
   * @see Calendar#set(int, int)
   */
  abstract public void roll(int field, boolean up);

  /**
   * Adds the specified (signed) amount to the specified calendar field
   * without changing larger fields.  A negative amount means to roll
   * down.
   *
   * <p>NOTE:  This default implementation on <code>Calendar</code> just repeatedly calls the
   * version of {@link #roll(int, boolean) roll()} that rolls by one unit.  This may not
   * always do the right thing.  For example, if the <code>DAY_OF_MONTH</code> field is 31,
   * rolling through February will leave it set to 28.  The <code>GregorianCalendar</code>
   * version of this function takes care of this problem.  Other subclasses
   * should also provide overrides of this function that do the right thing.
   *
   * @param field the calendar field.
   * @param amount the signed amount to add to the calendar <code>field</code>.
   * @see #roll(int, boolean)
   * @see #add(int, int)
   * @see #set(int, int)
   * @since 1.2
   */
  public void roll(int field, int amount) {
    while (amount > 0) {
      roll(field, true);
      amount--;
    }
    while (amount < 0) {
      roll(field, false);
      amount++;
    }
  }

  /**
   * Sets the time zone with the given time zone value.
   *
   * @param value the given time zone.
   */
  public void setTimeZone(TimeZone value) {
    zone = value;
    sharedZone = false;
        /* Recompute the fields from the time using the new zone.  This also
         * works if isTimeSet is false (after a call to set()).  In that case
         * the time will be computed from the fields using the new zone, then
         * the fields will get recomputed from that.  Consider the sequence of
         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
         * AFTER it up to the next call to complete().
         */
    areAllFieldsSet = areFieldsSet = false;
  }

  /**
   * Gets the time zone.
   *
   * @return the time zone object associated with this calendar.
   */
  public TimeZone getTimeZone() {
    // If the TimeZone object is shared by other Calendar instances, then
    // create a clone.
    if (sharedZone) {
      zone = (TimeZone) zone.clone();
      sharedZone = false;
    }
    return zone;
  }

  /**
   * Returns the time zone (without cloning).
   */
  TimeZone getZone() {
    return zone;
  }

  /**
   * Sets the sharedZone flag to <code>shared</code>.
   */
  void setZoneShared(boolean shared) {
    sharedZone = shared;
  }

  /**
   * Specifies whether or not date/time interpretation is to be lenient.  With
   * lenient interpretation, a date such as "February 942, 1996" will be
   * treated as being equivalent to the 941st day after February 1, 1996.
   * With strict (non-lenient) interpretation, such dates will cause an exception to be
   * thrown. The default is lenient.
   *
   * @param lenient <code>true</code> if the lenient mode is to be turned on; <code>false</code> if
   * it is to be turned off.
   * @see #isLenient()
   * @see java.text.DateFormat#setLenient
   */
  public void setLenient(boolean lenient) {
    this.lenient = lenient;
  }

  /**
   * Tells whether date/time interpretation is to be lenient.
   *
   * @return <code>true</code> if the interpretation mode of this calendar is lenient;
   * <code>false</code> otherwise.
   * @see #setLenient(boolean)
   */
  public boolean isLenient() {
    return lenient;
  }

  /**
   * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
   * <code>MONDAY</code> in France.
   *
   * @param value the given first day of the week.
   * @see #getFirstDayOfWeek()
   * @see #getMinimalDaysInFirstWeek()
   */
  public void setFirstDayOfWeek(int value) {
    if (firstDayOfWeek == value) {
      return;
    }
    firstDayOfWeek = value;
    invalidateWeekFields();
  }

  /**
   * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
   * <code>MONDAY</code> in France.
   *
   * @return the first day of the week.
   * @see #setFirstDayOfWeek(int)
   * @see #getMinimalDaysInFirstWeek()
   */
  public int getFirstDayOfWeek() {
    return firstDayOfWeek;
  }

  /**
   * Sets what the minimal days required in the first week of the year are;
   * For example, if the first week is defined as one that contains the first
   * day of the first month of a year, call this method with value 1. If it
   * must be a full week, use value 7.
   *
   * @param value the given minimal days required in the first week of the year.
   * @see #getMinimalDaysInFirstWeek()
   */
  public void setMinimalDaysInFirstWeek(int value) {
    if (minimalDaysInFirstWeek == value) {
      return;
    }
    minimalDaysInFirstWeek = value;
    invalidateWeekFields();
  }

  /**
   * Gets what the minimal days required in the first week of the year are;
   * e.g., if the first week is defined as one that contains the first day
   * of the first month of a year, this method returns 1. If
   * the minimal days required must be a full week, this method
   * returns 7.
   *
   * @return the minimal days required in the first week of the year.
   * @see #setMinimalDaysInFirstWeek(int)
   */
  public int getMinimalDaysInFirstWeek() {
    return minimalDaysInFirstWeek;
  }

  /**
   * Returns whether this {@code Calendar} supports week dates.
   *
   * <p>The default implementation of this method returns {@code false}.
   *
   * @return {@code true} if this {@code Calendar} supports week dates; {@code false} otherwise.
   * @see #getWeekYear()
   * @see #setWeekDate(int, int, int)
   * @see #getWeeksInWeekYear()
   * @since 1.7
   */
  public boolean isWeekDateSupported() {
    return false;
  }

  /**
   * Returns the week year represented by this {@code Calendar}. The
   * week year is in sync with the week cycle. The {@linkplain
   * #getFirstDayOfWeek() first day of the first week} is the first
   * day of the week year.
   *
   * <p>The default implementation of this method throws an
   * {@link UnsupportedOperationException}.
   *
   * @return the week year of this {@code Calendar}
   * @throws UnsupportedOperationException if any week year numbering isn't supported in this {@code
   * Calendar}.
   * @see #isWeekDateSupported()
   * @see #getFirstDayOfWeek()
   * @see #getMinimalDaysInFirstWeek()
   * @since 1.7
   */
  public int getWeekYear() {
    throw new UnsupportedOperationException();
  }

  /**
   * Sets the date of this {@code Calendar} with the the given date
   * specifiers - week year, week of year, and day of week.
   *
   * <p>Unlike the {@code set} method, all of the calendar fields
   * and {@code time} values are calculated upon return.
   *
   * <p>If {@code weekOfYear} is out of the valid week-of-year range
   * in {@code weekYear}, the {@code weekYear} and {@code
   * weekOfYear} values are adjusted in lenient mode, or an {@code
   * IllegalArgumentException} is thrown in non-lenient mode.
   *
   * <p>The default implementation of this method throws an
   * {@code UnsupportedOperationException}.
   *
   * @param weekYear the week year
   * @param weekOfYear the week number based on {@code weekYear}
   * @param dayOfWeek the day of week value: one of the constants for the {@link #DAY_OF_WEEK}
   * field: {@link #SUNDAY}, ..., {@link #SATURDAY}.
   * @throws IllegalArgumentException if any of the given date specifiers is invalid or any of the
   * calendar fields are inconsistent with the given date specifiers in non-lenient mode
   * @throws UnsupportedOperationException if any week year numbering isn't supported in this {@code
   * Calendar}.
   * @see #isWeekDateSupported()
   * @see #getFirstDayOfWeek()
   * @see #getMinimalDaysInFirstWeek()
   * @since 1.7
   */
  public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
    throw new UnsupportedOperationException();
  }

  /**
   * Returns the number of weeks in the week year represented by this
   * {@code Calendar}.
   *
   * <p>The default implementation of this method throws an
   * {@code UnsupportedOperationException}.
   *
   * @return the number of weeks in the week year.
   * @throws UnsupportedOperationException if any week year numbering isn't supported in this {@code
   * Calendar}.
   * @see #WEEK_OF_YEAR
   * @see #isWeekDateSupported()
   * @see #getWeekYear()
   * @see #getActualMaximum(int)
   * @since 1.7
   */
  public int getWeeksInWeekYear() {
    throw new UnsupportedOperationException();
  }

  /**
   * Returns the minimum value for the given calendar field of this
   * <code>Calendar</code> instance. The minimum value is defined as
   * the smallest value returned by the {@link #get(int) get} method
   * for any possible time value.  The minimum value depends on
   * calendar system specific parameters of the instance.
   *
   * @param field the calendar field.
   * @return the minimum value for the given calendar field.
   * @see #getMaximum(int)
   * @see #getGreatestMinimum(int)
   * @see #getLeastMaximum(int)
   * @see #getActualMinimum(int)
   * @see #getActualMaximum(int)
   */
  abstract public int getMinimum(int field);

  /**
   * Returns the maximum value for the given calendar field of this
   * <code>Calendar</code> instance. The maximum value is defined as
   * the largest value returned by the {@link #get(int) get} method
   * for any possible time value. The maximum value depends on
   * calendar system specific parameters of the instance.
   *
   * @param field the calendar field.
   * @return the maximum value for the given calendar field.
   * @see #getMinimum(int)
   * @see #getGreatestMinimum(int)
   * @see #getLeastMaximum(int)
   * @see #getActualMinimum(int)
   * @see #getActualMaximum(int)
   */
  abstract public int getMaximum(int field);

  /**
   * Returns the highest minimum value for the given calendar field
   * of this <code>Calendar</code> instance. The highest minimum
   * value is defined as the largest value returned by {@link
   * #getActualMinimum(int)} for any possible time value. The
   * greatest minimum value depends on calendar system specific
   * parameters of the instance.
   *
   * @param field the calendar field.
   * @return the highest minimum value for the given calendar field.
   * @see #getMinimum(int)
   * @see #getMaximum(int)
   * @see #getLeastMaximum(int)
   * @see #getActualMinimum(int)
   * @see #getActualMaximum(int)
   */
  abstract public int getGreatestMinimum(int field);

  /**
   * Returns the lowest maximum value for the given calendar field
   * of this <code>Calendar</code> instance. The lowest maximum
   * value is defined as the smallest value returned by {@link
   * #getActualMaximum(int)} for any possible time value. The least
   * maximum value depends on calendar system specific parameters of
   * the instance. For example, a <code>Calendar</code> for the
   * Gregorian calendar system returns 28 for the
   * <code>DAY_OF_MONTH</code> field, because the 28th is the last
   * day of the shortest month of this calendar, February in a
   * common year.
   *
   * @param field the calendar field.
   * @return the lowest maximum value for the given calendar field.
   * @see #getMinimum(int)
   * @see #getMaximum(int)
   * @see #getGreatestMinimum(int)
   * @see #getActualMinimum(int)
   * @see #getActualMaximum(int)
   */
  abstract public int getLeastMaximum(int field);

  /**
   * Returns the minimum value that the specified calendar field
   * could have, given the time value of this <code>Calendar</code>.
   *
   * <p>The default implementation of this method uses an iterative
   * algorithm to determine the actual minimum value for the
   * calendar field. Subclasses should, if possible, override this
   * with a more efficient implementation - in many cases, they can
   * simply return <code>getMinimum()</code>.
   *
   * @param field the calendar field
   * @return the minimum of the given calendar field for the time value of this
   * <code>Calendar</code>
   * @see #getMinimum(int)
   * @see #getMaximum(int)
   * @see #getGreatestMinimum(int)
   * @see #getLeastMaximum(int)
   * @see #getActualMaximum(int)
   * @since 1.2
   */
  public int getActualMinimum(int field) {
    int fieldValue = getGreatestMinimum(field);
    int endValue = getMinimum(field);

    // if we know that the minimum value is always the same, just return it
    if (fieldValue == endValue) {
      return fieldValue;
    }

    // clone the calendar so we don't mess with the real one, and set it to
    // accept anything for the field values
    Calendar work = (Calendar) this.clone();
    work.setLenient(true);

    // now try each value from getLeastMaximum() to getMaximum() one by one until
    // we get a value that normalizes to another value.  The last value that
    // normalizes to itself is the actual minimum for the current date
    int result = fieldValue;

    do {
      work.set(field, fieldValue);
      if (work.get(field) != fieldValue) {
        break;
      } else {
        result = fieldValue;
        fieldValue--;
      }
    } while (fieldValue >= endValue);

    return result;
  }

  /**
   * Returns the maximum value that the specified calendar field
   * could have, given the time value of this
   * <code>Calendar</code>. For example, the actual maximum value of
   * the <code>MONTH</code> field is 12 in some years, and 13 in
   * other years in the Hebrew calendar system.
   *
   * <p>The default implementation of this method uses an iterative
   * algorithm to determine the actual maximum value for the
   * calendar field. Subclasses should, if possible, override this
   * with a more efficient implementation.
   *
   * @param field the calendar field
   * @return the maximum of the given calendar field for the time value of this
   * <code>Calendar</code>
   * @see #getMinimum(int)
   * @see #getMaximum(int)
   * @see #getGreatestMinimum(int)
   * @see #getLeastMaximum(int)
   * @see #getActualMinimum(int)
   * @since 1.2
   */
  public int getActualMaximum(int field) {
    int fieldValue = getLeastMaximum(field);
    int endValue = getMaximum(field);

    // if we know that the maximum value is always the same, just return it.
    if (fieldValue == endValue) {
      return fieldValue;
    }

    // clone the calendar so we don't mess with the real one, and set it to
    // accept anything for the field values.
    Calendar work = (Calendar) this.clone();
    work.setLenient(true);

    // if we're counting weeks, set the day of the week to Sunday.  We know the
    // last week of a month or year will contain the first day of the week.
    if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) {
      work.set(DAY_OF_WEEK, firstDayOfWeek);
    }

    // now try each value from getLeastMaximum() to getMaximum() one by one until
    // we get a value that normalizes to another value.  The last value that
    // normalizes to itself is the actual maximum for the current date
    int result = fieldValue;

    do {
      work.set(field, fieldValue);
      if (work.get(field) != fieldValue) {
        break;
      } else {
        result = fieldValue;
        fieldValue++;
      }
    } while (fieldValue <= endValue);

    return result;
  }

  /**
   * Creates and returns a copy of this object.
   *
   * @return a copy of this object.
   */
  @Override
  public Object clone() {
    try {
      Calendar other = (Calendar) super.clone();

      other.fields = new int[FIELD_COUNT];
      other.isSet = new boolean[FIELD_COUNT];
      other.stamp = new int[FIELD_COUNT];
      for (int i = 0; i < FIELD_COUNT; i++) {
        other.fields[i] = fields[i];
        other.stamp[i] = stamp[i];
        other.isSet[i] = isSet[i];
      }
      other.zone = (TimeZone) zone.clone();
      return other;
    } catch (CloneNotSupportedException e) {
      // this shouldn't happen, since we are Cloneable
      throw new InternalError(e);
    }
  }

  private static final String[] FIELD_NAME = {
      "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
      "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
      "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
      "DST_OFFSET"
  };

  /**
   * Returns the name of the specified calendar field.
   *
   * @param field the calendar field
   * @return the calendar field name
   * @throws IndexOutOfBoundsException if <code>field</code> is negative, equal to or greater then
   * <code>FIELD_COUNT</code>.
   */
  static String getFieldName(int field) {
    return FIELD_NAME[field];
  }

  /**
   * Return a string representation of this calendar. This method
   * is intended to be used only for debugging purposes, and the
   * format of the returned string may vary between implementations.
   * The returned string may be empty but may not be <code>null</code>.
   *
   * @return a string representation of this calendar.
   */
  @Override
  public String toString() {
    // NOTE: BuddhistCalendar.toString() interprets the string
    // produced by this method so that the Gregorian year number
    // is substituted by its B.E. year value. It relies on
    // "...,YEAR=<year>,..." or "...,YEAR=?,...".
    StringBuilder buffer = new StringBuilder(800);
    buffer.append(getClass().getName()).append('[');
    appendValue(buffer, "time", isTimeSet, time);
    buffer.append(",areFieldsSet=").append(areFieldsSet);
    buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
    buffer.append(",lenient=").append(lenient);
    buffer.append(",zone=").append(zone);
    appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
    appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
    for (int i = 0; i < FIELD_COUNT; ++i) {
      buffer.append(',');
      appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
    }
    buffer.append(']');
    return buffer.toString();
  }

  // =======================privates===============================

  private static void appendValue(StringBuilder sb, String item, boolean valid, long value) {
    sb.append(item).append('=');
    if (valid) {
      sb.append(value);
    } else {
      sb.append('?');
    }
  }

  /**
   * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
   * They are used to figure out the week count for a specific date for
   * a given locale. These must be set when a Calendar is constructed.
   *
   * @param desiredLocale the given locale.
   */
  private void setWeekCountData(Locale desiredLocale) {
        /* try to get the Locale data from the cache */
    int[] data = cachedLocaleData.get(desiredLocale);
    if (data == null) {  /* cache miss */
      data = new int[2];
      data[0] = CalendarDataUtility.retrieveFirstDayOfWeek(desiredLocale);
      data[1] = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(desiredLocale);
      cachedLocaleData.putIfAbsent(desiredLocale, data);
    }
    firstDayOfWeek = data[0];
    minimalDaysInFirstWeek = data[1];
  }

  /**
   * Recomputes the time and updates the status fields isTimeSet
   * and areFieldsSet.  Callers should check isTimeSet and only
   * call this method if isTimeSet is false.
   */
  private void updateTime() {
    computeTime();
    // The areFieldsSet and areAllFieldsSet values are no longer
    // controlled here (as of 1.5).
    isTimeSet = true;
  }

  private int compareTo(long t) {
    long thisTime = getMillisOf(this);
    return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
  }

  private static long getMillisOf(Calendar calendar) {
    if (calendar.isTimeSet) {
      return calendar.time;
    }
    Calendar cal = (Calendar) calendar.clone();
    cal.setLenient(true);
    return cal.getTimeInMillis();
  }

  /**
   * Adjusts the stamp[] values before nextStamp overflow. nextStamp
   * is set to the next stamp value upon the return.
   */
  private void adjustStamp() {
    int max = MINIMUM_USER_STAMP;
    int newStamp = MINIMUM_USER_STAMP;

    for (; ; ) {
      int min = Integer.MAX_VALUE;
      for (int i = 0; i < stamp.length; i++) {
        int v = stamp[i];
        if (v >= newStamp && min > v) {
          min = v;
        }
        if (max < v) {
          max = v;
        }
      }
      if (max != min && min == Integer.MAX_VALUE) {
        break;
      }
      for (int i = 0; i < stamp.length; i++) {
        if (stamp[i] == min) {
          stamp[i] = newStamp;
        }
      }
      newStamp++;
      if (min == max) {
        break;
      }
    }
    nextStamp = newStamp;
  }

  /**
   * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
   * new parameter value if they have been calculated internally.
   */
  private void invalidateWeekFields() {
    if (stamp[WEEK_OF_MONTH] != COMPUTED &&
        stamp[WEEK_OF_YEAR] != COMPUTED) {
      return;
    }

    // We have to check the new values of these fields after changing
    // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
    // have been changed, then set the new values. (4822110)
    Calendar cal = (Calendar) clone();
    cal.setLenient(true);
    cal.clear(WEEK_OF_MONTH);
    cal.clear(WEEK_OF_YEAR);

    if (stamp[WEEK_OF_MONTH] == COMPUTED) {
      int weekOfMonth = cal.get(WEEK_OF_MONTH);
      if (fields[WEEK_OF_MONTH] != weekOfMonth) {
        fields[WEEK_OF_MONTH] = weekOfMonth;
      }
    }

    if (stamp[WEEK_OF_YEAR] == COMPUTED) {
      int weekOfYear = cal.get(WEEK_OF_YEAR);
      if (fields[WEEK_OF_YEAR] != weekOfYear) {
        fields[WEEK_OF_YEAR] = weekOfYear;
      }
    }
  }

  /**
   * Save the state of this object to a stream (i.e., serialize it).
   *
   * Ideally, <code>Calendar</code> would only write out its state data and
   * the current time, and not write any field data out, such as
   * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
   * and <code>isSet[]</code>.  <code>nextStamp</code> also should not be part
   * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
   * shipped. To be compatible with JDK 1.1, we will always have to write out
   * the field values and state flags.  However, <code>nextStamp</code> can be
   * removed from the serialization stream; this will probably happen in the
   * near future.
   */
  private synchronized void writeObject(ObjectOutputStream stream)
      throws IOException {
    // Try to compute the time correctly, for the future (stream
    // version 2) in which we don't write out fields[] or isSet[].
    if (!isTimeSet) {
      try {
        updateTime();
      } catch (IllegalArgumentException e) {
      }
    }

    // If this Calendar has a ZoneInfo, save it and set a
    // SimpleTimeZone equivalent (as a single DST schedule) for
    // backward compatibility.
    TimeZone savedZone = null;
    if (zone instanceof ZoneInfo) {
      SimpleTimeZone stz = ((ZoneInfo) zone).getLastRuleInstance();
      if (stz == null) {
        stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
      }
      savedZone = zone;
      zone = stz;
    }

    // Write out the 1.1 FCS object.
    stream.defaultWriteObject();

    // Write out the ZoneInfo object
    // 4802409: we write out even if it is null, a temporary workaround
    // the real fix for bug 4844924 in corba-iiop
    stream.writeObject(savedZone);
    if (savedZone != null) {
      zone = savedZone;
    }
  }

  private static class CalendarAccessControlContext {

    private static final AccessControlContext INSTANCE;

    static {
      RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
      PermissionCollection perms = perm.newPermissionCollection();
      perms.add(perm);
      INSTANCE = new AccessControlContext(new ProtectionDomain[]{
          new ProtectionDomain(null, perms)
      });
    }

    private CalendarAccessControlContext() {
    }
  }

  /**
   * Reconstitutes this object from a stream (i.e., deserialize it).
   */
  private void readObject(ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
    final ObjectInputStream input = stream;
    input.defaultReadObject();

    stamp = new int[FIELD_COUNT];

    // Starting with version 2 (not implemented yet), we expect that
    // fields[], isSet[], isTimeSet, and areFieldsSet may not be
    // streamed out anymore.  We expect 'time' to be correct.
    if (serialVersionOnStream >= 2) {
      isTimeSet = true;
      if (fields == null) {
        fields = new int[FIELD_COUNT];
      }
      if (isSet == null) {
        isSet = new boolean[FIELD_COUNT];
      }
    } else if (serialVersionOnStream >= 0) {
      for (int i = 0; i < FIELD_COUNT; ++i) {
        stamp[i] = isSet[i] ? COMPUTED : UNSET;
      }
    }

    serialVersionOnStream = currentSerialVersion;

    // If there's a ZoneInfo object, use it for zone.
    ZoneInfo zi = null;
    try {
      zi = AccessController.doPrivileged(
          new PrivilegedExceptionAction<ZoneInfo>() {
            @Override
            public ZoneInfo run() throws Exception {
              return (ZoneInfo) input.readObject();
            }
          },
          CalendarAccessControlContext.INSTANCE);
    } catch (PrivilegedActionException pae) {
      Exception e = pae.getException();
      if (!(e instanceof OptionalDataException)) {
        if (e instanceof RuntimeException) {
          throw (RuntimeException) e;
        } else if (e instanceof IOException) {
          throw (IOException) e;
        } else if (e instanceof ClassNotFoundException) {
          throw (ClassNotFoundException) e;
        }
        throw new RuntimeException(e);
      }
    }
    if (zi != null) {
      zone = zi;
    }

    // If the deserialized object has a SimpleTimeZone, try to
    // replace it with a ZoneInfo equivalent (as of 1.4) in order
    // to be compatible with the SimpleTimeZone-based
    // implementation as much as possible.
    if (zone instanceof SimpleTimeZone) {
      String id = zone.getID();
      TimeZone tz = TimeZone.getTimeZone(id);
      if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
        zone = tz;
      }
    }
  }

  /**
   * Converts this object to an {@link Instant}.
   * <p>
   * The conversion creates an {@code Instant} that represents the
   * same point on the time-line as this {@code Calendar}.
   *
   * @return the instant representing the same point on the time-line
   * @since 1.8
   */
  public final Instant toInstant() {
    return Instant.ofEpochMilli(getTimeInMillis());
  }
}
